ahoward-helene 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +274 -0
- data/helene.gemspec +26 -0
- data/lib/helene.rb +113 -0
- data/lib/helene/attempt.rb +46 -0
- data/lib/helene/aws.rb +50 -0
- data/lib/helene/config.rb +147 -0
- data/lib/helene/content_type.rb +15 -0
- data/lib/helene/content_type.yml +661 -0
- data/lib/helene/error.rb +12 -0
- data/lib/helene/logging.rb +55 -0
- data/lib/helene/objectpool.rb +220 -0
- data/lib/helene/rails.rb +21 -0
- data/lib/helene/rightscale/acf/right_acf_interface.rb +379 -0
- data/lib/helene/rightscale/awsbase/benchmark_fix.rb +39 -0
- data/lib/helene/rightscale/awsbase/right_awsbase.rb +803 -0
- data/lib/helene/rightscale/awsbase/support.rb +111 -0
- data/lib/helene/rightscale/ec2/right_ec2.rb +1737 -0
- data/lib/helene/rightscale/net_fix.rb +160 -0
- data/lib/helene/rightscale/right_aws.rb +71 -0
- data/lib/helene/rightscale/right_http_connection.rb +507 -0
- data/lib/helene/rightscale/s3/right_s3.rb +1094 -0
- data/lib/helene/rightscale/s3/right_s3_interface.rb +1180 -0
- data/lib/helene/rightscale/sdb/active_sdb.rb +930 -0
- data/lib/helene/rightscale/sdb/right_sdb_interface.rb +696 -0
- data/lib/helene/rightscale/sqs/right_sqs.rb +388 -0
- data/lib/helene/rightscale/sqs/right_sqs_gen2.rb +286 -0
- data/lib/helene/rightscale/sqs/right_sqs_gen2_interface.rb +444 -0
- data/lib/helene/rightscale/sqs/right_sqs_interface.rb +596 -0
- data/lib/helene/s3.rb +34 -0
- data/lib/helene/s3/bucket.rb +379 -0
- data/lib/helene/s3/grantee.rb +134 -0
- data/lib/helene/s3/key.rb +162 -0
- data/lib/helene/s3/owner.rb +16 -0
- data/lib/helene/sdb.rb +9 -0
- data/lib/helene/sdb/base.rb +1204 -0
- data/lib/helene/sdb/base/associations.rb +481 -0
- data/lib/helene/sdb/base/attributes.rb +90 -0
- data/lib/helene/sdb/base/connection.rb +20 -0
- data/lib/helene/sdb/base/error.rb +20 -0
- data/lib/helene/sdb/base/hooks.rb +82 -0
- data/lib/helene/sdb/base/literal.rb +52 -0
- data/lib/helene/sdb/base/logging.rb +23 -0
- data/lib/helene/sdb/base/transactions.rb +53 -0
- data/lib/helene/sdb/base/type.rb +137 -0
- data/lib/helene/sdb/base/types.rb +123 -0
- data/lib/helene/sdb/base/validations.rb +256 -0
- data/lib/helene/sdb/cast.rb +114 -0
- data/lib/helene/sdb/connection.rb +36 -0
- data/lib/helene/sdb/error.rb +5 -0
- data/lib/helene/sdb/interface.rb +412 -0
- data/lib/helene/sdb/sentinel.rb +15 -0
- data/lib/helene/sleepcycle.rb +29 -0
- data/lib/helene/superhash.rb +297 -0
- data/lib/helene/util.rb +132 -0
- data/test/auth.rb +31 -0
- data/test/helper.rb +98 -0
- data/test/integration/begin.rb +0 -0
- data/test/integration/ensure.rb +8 -0
- data/test/integration/s3/bucket.rb +106 -0
- data/test/integration/sdb/associations.rb +45 -0
- data/test/integration/sdb/creating.rb +13 -0
- data/test/integration/sdb/emptiness.rb +56 -0
- data/test/integration/sdb/hooks.rb +19 -0
- data/test/integration/sdb/limits.rb +27 -0
- data/test/integration/sdb/saving.rb +21 -0
- data/test/integration/sdb/selecting.rb +39 -0
- data/test/integration/sdb/types.rb +31 -0
- data/test/integration/sdb/validations.rb +60 -0
- data/test/integration/setup.rb +27 -0
- data/test/integration/teardown.rb +21 -0
- data/test/loader.rb +39 -0
- metadata +139 -0
data/lib/helene/s3.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
module Helene
|
2
|
+
module S3
|
3
|
+
class << S3
|
4
|
+
def thread
|
5
|
+
Thread.current
|
6
|
+
end
|
7
|
+
|
8
|
+
def establish_connection(aws_access_key_id=Helene.aws_access_key_id, aws_secret_access_key=Helene.aws_secret_access_key, options={})
|
9
|
+
options.to_options!
|
10
|
+
thread[:helene_s3_interface] = RightAws::S3Interface.new(aws_access_key_id, aws_secret_access_key, options)
|
11
|
+
raise Error, 'Connection to S3 is not established' unless thread[:helene_s3_interface]
|
12
|
+
|
13
|
+
thread[:helene_s3_generator] = RightAws::S3Generator.new(aws_access_key_id, aws_secret_access_key)
|
14
|
+
raise Error, 'Connection to S3 is not established' unless thread[:helene_s3_generator]
|
15
|
+
end
|
16
|
+
|
17
|
+
def interface
|
18
|
+
establish_connection unless thread[:helene_s3_interface]
|
19
|
+
thread[:helene_s3_interface]
|
20
|
+
end
|
21
|
+
alias_method 'connection', 'interface'
|
22
|
+
|
23
|
+
def s3g
|
24
|
+
establish_connection unless thread[:helene_s3_generator]
|
25
|
+
thread[:helene_s3_generator]
|
26
|
+
end
|
27
|
+
|
28
|
+
load 'helene/s3/bucket.rb'
|
29
|
+
load 'helene/s3/key.rb'
|
30
|
+
load 'helene/s3/owner.rb'
|
31
|
+
load 'helene/s3/grantee.rb'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,379 @@
|
|
1
|
+
module Helene
|
2
|
+
module S3
|
3
|
+
class Bucket
|
4
|
+
class << Bucket
|
5
|
+
def interface
|
6
|
+
S3.interface
|
7
|
+
end
|
8
|
+
|
9
|
+
def list(&block)
|
10
|
+
list = []
|
11
|
+
interface.list_all_my_buckets.map! do |entry|
|
12
|
+
owner = Owner.new(entry[:owner_id], entry[:owner_display_name])
|
13
|
+
bucket = allocate
|
14
|
+
name = entry[:name]
|
15
|
+
creation_date = entry[:creation_date]
|
16
|
+
options = {:interface => interface, :owner => owner, :creation_date => creation_date}
|
17
|
+
bucket.send(:initialize, name, options)
|
18
|
+
block ? block.all(bucket) : list.push(bucket)
|
19
|
+
end
|
20
|
+
block ? nil : list
|
21
|
+
end
|
22
|
+
alias_method 'buckets', 'list'
|
23
|
+
|
24
|
+
def create(name, options = {})
|
25
|
+
options.to_options!
|
26
|
+
headers = options.delete(:headers) || {}
|
27
|
+
interface.create_bucket(name, headers)
|
28
|
+
new(name)
|
29
|
+
end
|
30
|
+
|
31
|
+
def new(name, options = {})
|
32
|
+
result = S3.interface.list_bucket(name.to_s)
|
33
|
+
service = result.service
|
34
|
+
owner = Owner.new(service[:owner_id], service[:owner_display_name])
|
35
|
+
bucket = allocate
|
36
|
+
name = service[:name]
|
37
|
+
options[:interface] || S3.interface
|
38
|
+
options[:owner] ||= owner
|
39
|
+
options[:creation_date] ||= service[:creation_date]
|
40
|
+
bucket.send(:initialize, name, options)
|
41
|
+
owner, grantees = Grantee.owner_and_grantees(bucket)
|
42
|
+
bucket.owner = owner
|
43
|
+
bucket
|
44
|
+
end
|
45
|
+
alias_method 'for', 'new'
|
46
|
+
|
47
|
+
def url(*args)
|
48
|
+
options = args.extract_options!.to_options!
|
49
|
+
options.to_options!
|
50
|
+
expires = options[:expires] || 24.hours
|
51
|
+
headers = options.delete(:headers) || {}
|
52
|
+
case args.shift.to_s
|
53
|
+
when '', 'list'
|
54
|
+
interface.list_all_my_buckets_link(expires, headers)
|
55
|
+
when 'create'
|
56
|
+
bucket = args.shift.to_s
|
57
|
+
interface.create_bucket_link(bucket, expires, headers)
|
58
|
+
when 'delete'
|
59
|
+
bucket = args.shift.to_s
|
60
|
+
interface.delete_bucket_link(bucket, expires, headers)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
alias_method 'url_for', 'url'
|
64
|
+
|
65
|
+
def delete(bucket, options ={})
|
66
|
+
options.to_options!
|
67
|
+
force = options.delete(:force)
|
68
|
+
name = bucket.is_a?(Bucket) ? bucket.name : bucket.to_s
|
69
|
+
force ? interface.force_delete_bucket(name) : interface.delete_bucket(name)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
attr_accessor :name
|
74
|
+
attr_accessor :interface
|
75
|
+
attr_accessor :owner
|
76
|
+
attr_accessor :creation_date
|
77
|
+
attr :prefix
|
78
|
+
|
79
|
+
def initialize(name, *args)
|
80
|
+
options = args.extract_options!.to_options!
|
81
|
+
@name = name.to_s
|
82
|
+
@interface = options[:interface] || S3.interface
|
83
|
+
@owner = options[:owner]
|
84
|
+
@creation_date = options[:creation_date]
|
85
|
+
@prefix = cleanpath(options[:prefix]) if options[:prefix]
|
86
|
+
if @creation_date && !@creation_date.is_a?(Time)
|
87
|
+
@creation_date = Time.parse(@creation_date)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def prefix= *prefixes
|
92
|
+
@prefix = cleanpath(*prefixes)
|
93
|
+
end
|
94
|
+
|
95
|
+
def to_s
|
96
|
+
@name.to_s
|
97
|
+
end
|
98
|
+
|
99
|
+
def == other
|
100
|
+
name == other.name and prefix == other.prefix
|
101
|
+
end
|
102
|
+
|
103
|
+
def cleanpath(*paths)
|
104
|
+
path = File.join(*paths.flatten.compact)
|
105
|
+
path = path.to_s.strip
|
106
|
+
path.sub! %r|^[./]+|, ''
|
107
|
+
path.sub! %r|/*$|, '/'
|
108
|
+
path.squeeze! '/'
|
109
|
+
path
|
110
|
+
end
|
111
|
+
|
112
|
+
def prefixed(path, &block)
|
113
|
+
path = path.to_s
|
114
|
+
absolute = path =~ %r|^/|
|
115
|
+
if absolute
|
116
|
+
path[1..-1]
|
117
|
+
else
|
118
|
+
return scoping(path, &block) if block
|
119
|
+
@prefix ? File.join(@prefix, path) : path
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def scoping(suffix, &block)
|
124
|
+
old = @prefix
|
125
|
+
@prefix = cleanpath(@prefix, suffix)
|
126
|
+
block.call
|
127
|
+
ensure
|
128
|
+
@prefix = old
|
129
|
+
end
|
130
|
+
alias_method 'suffixing', 'scoping'
|
131
|
+
|
132
|
+
def / suffix
|
133
|
+
bucket = clone
|
134
|
+
bucket.prefix = cleanpath(@prefix, suffix)
|
135
|
+
bucket
|
136
|
+
end
|
137
|
+
|
138
|
+
def put(data, *args, &block)
|
139
|
+
options = args.extract_options!.to_options!
|
140
|
+
|
141
|
+
meta = options.delete(:meta) || {}
|
142
|
+
perms = options.delete(:perms)
|
143
|
+
headers = options.delete(:headers) || {}
|
144
|
+
|
145
|
+
io_for(data) do |io|
|
146
|
+
path = args.shift || path_for(io)
|
147
|
+
key = key_for(path, io, meta)
|
148
|
+
headers = headers_for(path, headers)
|
149
|
+
key.put(io, perms, headers)
|
150
|
+
key
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def get(path, *args, &block)
|
155
|
+
options = args.extract_options!.to_options!
|
156
|
+
headers = options.delete(:headers) || {}
|
157
|
+
key = key_for(path)
|
158
|
+
key.get(headers)
|
159
|
+
end
|
160
|
+
|
161
|
+
def io_for(arg)
|
162
|
+
return(arg.respond_to?(:read) ? yield(arg) : open(arg.to_s){|io| yield(io)})
|
163
|
+
end
|
164
|
+
|
165
|
+
def path_for(arg)
|
166
|
+
path = nil
|
167
|
+
%w[ path pathname filename ].each do |msg|
|
168
|
+
if arg.respond_to?(msg)
|
169
|
+
path = File.basename(arg.send(msg).to_s)
|
170
|
+
break path
|
171
|
+
end
|
172
|
+
end
|
173
|
+
raise Errror, "no path from #{ arg.inspect }" if path.blank?
|
174
|
+
cleanpath(path)
|
175
|
+
end
|
176
|
+
|
177
|
+
def key_for(arg, io = nil, meta = {})
|
178
|
+
return arg if arg.is_a?(Key)
|
179
|
+
Key.create(self, prefixed(arg.to_s), io, meta)
|
180
|
+
end
|
181
|
+
|
182
|
+
def headers_for(path, headers = {})
|
183
|
+
headers = HashWithIndifferentAccess.new(headers)
|
184
|
+
content_type = (
|
185
|
+
headers.delete(:content_type) ||
|
186
|
+
headers.delete(:Content_Type) ||
|
187
|
+
headers.delete(:ContentType) ||
|
188
|
+
content_type_for(path)
|
189
|
+
)
|
190
|
+
headers.merge!('Content-Type' => content_type) if content_type
|
191
|
+
headers
|
192
|
+
end
|
193
|
+
|
194
|
+
def content_type_for(basename)
|
195
|
+
Util.content_type_for(basename)
|
196
|
+
end
|
197
|
+
|
198
|
+
def url(*args)
|
199
|
+
options = args.extract_options!.to_options!
|
200
|
+
options.to_options!
|
201
|
+
method = options.delete(:method) || args.shift.to_s
|
202
|
+
path = options.delete(:path) || args.shift
|
203
|
+
data = options.delete(:data) || args.shift
|
204
|
+
expires = options.delete(:expires) || 24.hours
|
205
|
+
query = options.delete(:query)
|
206
|
+
headers = options.delete(:headers) || {}
|
207
|
+
|
208
|
+
case method.to_s
|
209
|
+
when '', 'list'
|
210
|
+
(query ||= {})[:prefix] ||= prefix if prefix
|
211
|
+
interface.list_bucket_link(name, query, expires, headers)
|
212
|
+
when 'put'
|
213
|
+
interface.put_link(name, prefixed(path), data, expires, headers)
|
214
|
+
when 'get'
|
215
|
+
interface.get_link(name, prefixed(path), expires, headers)
|
216
|
+
when 'head'
|
217
|
+
interface.head_link(name, prefixed(path), expires, headers)
|
218
|
+
when 'delete'
|
219
|
+
interface.delete_link(name, prefixed(path), expires, headers)
|
220
|
+
when 'get_acl'
|
221
|
+
interface.get_acl_link(name, prefixed(path), headers)
|
222
|
+
when 'put_acl'
|
223
|
+
interface.put_acl_link(name, prefixed(path), headers)
|
224
|
+
when 'get_bucket_acl'
|
225
|
+
interface.get_bucket_acl_link(name, headers)
|
226
|
+
when 'put_bucket_acl'
|
227
|
+
interface.put_bucket_acl_link(name, headers)
|
228
|
+
else
|
229
|
+
raise ArgumentError, method.inspect
|
230
|
+
end
|
231
|
+
end
|
232
|
+
alias_method 'url_for', 'url'
|
233
|
+
|
234
|
+
def clear(options = {})
|
235
|
+
options.to_options!
|
236
|
+
prefix = options[:prefix] || @prefix
|
237
|
+
if prefix
|
238
|
+
@interface.delete_folder(@name, prefix)
|
239
|
+
else
|
240
|
+
@interface.clear_bucket(name)
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
def keys(options={}, &block)
|
245
|
+
options.to_options!
|
246
|
+
options[:prefix] ||= prefix
|
247
|
+
options.delete(:service)
|
248
|
+
keys_and_service(options, &block)
|
249
|
+
end
|
250
|
+
alias_method 'list', 'keys'
|
251
|
+
|
252
|
+
def ls(options = {}, &block)
|
253
|
+
names = []
|
254
|
+
keys do |key|
|
255
|
+
block ? block.call(key.name) : names.push(key.name)
|
256
|
+
end
|
257
|
+
block ? nil : names
|
258
|
+
end
|
259
|
+
|
260
|
+
# TODO - refactor messiness with service
|
261
|
+
#
|
262
|
+
def keys_and_service(options={}, &block)
|
263
|
+
options.to_options!
|
264
|
+
options[:prefix] ||= prefix
|
265
|
+
head = options.delete(:head)
|
266
|
+
wants_service = options.delete(:service)
|
267
|
+
service = {}
|
268
|
+
hash = {}
|
269
|
+
keys = []
|
270
|
+
@interface.incrementally_list_bucket(@name, options.stringify_keys) do |hash|
|
271
|
+
hash[:contents].each do |entry|
|
272
|
+
owner = Owner.new(entry[:owner_id], entry[:owner_display_name])
|
273
|
+
key = Key.new(self, entry[:key], nil, {}, {}, entry[:last_modified], entry[:e_tag], entry[:size], entry[:storage_class], owner)
|
274
|
+
key.head if head
|
275
|
+
block ? block.call(key) : keys.push(key)
|
276
|
+
end
|
277
|
+
end
|
278
|
+
if wants_service
|
279
|
+
hash.each_key do |key|
|
280
|
+
service[key] = hash[key] unless (key == :contents || key == :common_prefixes)
|
281
|
+
end
|
282
|
+
[keys, service]
|
283
|
+
else
|
284
|
+
block ? nil : keys
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
def key(path, options={}, &block)
|
289
|
+
options.to_options!
|
290
|
+
options[:prefix] ||= prefixed(path.to_s)
|
291
|
+
keys(options).first
|
292
|
+
end
|
293
|
+
alias_method '[]', 'key'
|
294
|
+
|
295
|
+
# TODO - refactor, possibly place in key.rb
|
296
|
+
#
|
297
|
+
def find_or_create_key_by_absolute_path(path, options = {})
|
298
|
+
path = path.to_s
|
299
|
+
options.to_options!
|
300
|
+
head = options.has_key?(:head) ? options.delete(:head) : true
|
301
|
+
key = nil
|
302
|
+
keys(:prefix => path, :head => head).each do |candidate|
|
303
|
+
break(key = candidate) if candidate.name == path
|
304
|
+
end
|
305
|
+
key ||= Key.create(self, path)
|
306
|
+
end
|
307
|
+
|
308
|
+
def has_key?(path)
|
309
|
+
find_or_create_key_by_absolute_path(prefixed(path)).exists?
|
310
|
+
end
|
311
|
+
|
312
|
+
def rename_key(src, dst)
|
313
|
+
src = Key.create(self, prefixed(src.to_s)) unless src.is_a?(Key)
|
314
|
+
src.rename(prefixed(dst))
|
315
|
+
src
|
316
|
+
end
|
317
|
+
alias_method 'rename', 'rename_key'
|
318
|
+
|
319
|
+
def copy_key(src, dst)
|
320
|
+
src = Key.create(self, prefixed(src.to_s)) unless src.is_a?(Key)
|
321
|
+
src.copy(prefixed(dst))
|
322
|
+
end
|
323
|
+
alias_method 'cp', 'copy_key'
|
324
|
+
alias_method 'copy', 'copy_key'
|
325
|
+
|
326
|
+
def move_key(src, dst)
|
327
|
+
src = Key.create(self, prefixed(src.to_s)) unless src.is_a?(Key)
|
328
|
+
src.move(prefixed(dst))
|
329
|
+
end
|
330
|
+
alias_method 'mv', 'move_key'
|
331
|
+
alias_method 'move', 'move_key'
|
332
|
+
|
333
|
+
def location # '' or 'EU'
|
334
|
+
@location ||= @interface.bucket_location(name)
|
335
|
+
end
|
336
|
+
|
337
|
+
# TODO - totally untested
|
338
|
+
#
|
339
|
+
def logging_info
|
340
|
+
@interface.get_logging_parse(:bucket => @name)
|
341
|
+
end
|
342
|
+
|
343
|
+
# TODO - totally untested
|
344
|
+
#
|
345
|
+
def enable_logging(params)
|
346
|
+
AwsUtils.mandatory_arguments([:targetbucket, :targetprefix], params)
|
347
|
+
AwsUtils.allow_only([:targetbucket, :targetprefix], params)
|
348
|
+
xmldoc =
|
349
|
+
"
|
350
|
+
<?xml version=\"1.0\" encoding=\"UTF-8\"?>
|
351
|
+
<BucketLoggingStatus xmlns=\"http://doc.s3.amazonaws.com/2006-03-01\">
|
352
|
+
<LoggingEnabled>
|
353
|
+
<TargetBucket>#{params[:targetbucket]}</TargetBucket>
|
354
|
+
<TargetPrefix>#{params[:targetprefix]}</TargetPrefix>
|
355
|
+
</LoggingEnabled></BucketLoggingStatus>
|
356
|
+
"
|
357
|
+
@interface.put_logging(:bucket => @name, :xmldoc => xmldoc)
|
358
|
+
end
|
359
|
+
|
360
|
+
# TODO - totally untested
|
361
|
+
#
|
362
|
+
def disable_logging
|
363
|
+
xmldoc =
|
364
|
+
"
|
365
|
+
<?xml version=\"1.0\" encoding=\"UTF-8\"?>
|
366
|
+
<BucketLoggingStatus xmlns=\"http://doc.s3.amazonaws.com/2006-03-01\">
|
367
|
+
</BucketLoggingStatus>
|
368
|
+
"
|
369
|
+
@interface.put_logging(:bucket => @name, :xmldoc => xmldoc)
|
370
|
+
end
|
371
|
+
|
372
|
+
# TODO - totally untested
|
373
|
+
#
|
374
|
+
def grantees
|
375
|
+
Grantee::grantees(self)
|
376
|
+
end
|
377
|
+
end
|
378
|
+
end
|
379
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
module Helene
|
2
|
+
module S3
|
3
|
+
class Grantee
|
4
|
+
attr_reader :thing
|
5
|
+
attr_reader :id
|
6
|
+
attr_reader :name
|
7
|
+
attr_accessor :perms
|
8
|
+
|
9
|
+
def self.owner_and_grantees(thing)
|
10
|
+
if thing.is_a?(Bucket)
|
11
|
+
bucket, key = thing, ''
|
12
|
+
else
|
13
|
+
bucket, key = thing.bucket, thing
|
14
|
+
end
|
15
|
+
hash = bucket.interface.get_acl_parse(bucket.to_s, key.to_s)
|
16
|
+
owner = Owner.new(hash[:owner][:id], hash[:owner][:display_name])
|
17
|
+
|
18
|
+
grantees = []
|
19
|
+
hash[:grantees].each do |id, params|
|
20
|
+
grantees << new(thing, id, params[:permissions], nil, params[:display_name])
|
21
|
+
end
|
22
|
+
[owner, grantees]
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.grantees(thing)
|
26
|
+
owner_and_grantees(thing)[1]
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.put_acl(thing, owner, grantees) #:nodoc:
|
30
|
+
if thing.is_a?(Bucket)
|
31
|
+
bucket, key = thing, ''
|
32
|
+
else
|
33
|
+
bucket, key = thing.bucket, thing
|
34
|
+
end
|
35
|
+
body = "<AccessControlPolicy>" +
|
36
|
+
"<Owner>" +
|
37
|
+
"<ID>#{owner.id}</ID>" +
|
38
|
+
"<DisplayName>#{owner.name}</DisplayName>" +
|
39
|
+
"</Owner>" +
|
40
|
+
"<AccessControlList>" +
|
41
|
+
grantees.map{|grantee| grantee.to_xml}.join +
|
42
|
+
"</AccessControlList>" +
|
43
|
+
"</AccessControlPolicy>"
|
44
|
+
bucket.interface.put_acl(bucket.to_s, key.to_s, body)
|
45
|
+
end
|
46
|
+
|
47
|
+
def initialize(thing, id, perms=[], action=:refresh, name=nil)
|
48
|
+
@thing = thing
|
49
|
+
@id = id
|
50
|
+
@name = name
|
51
|
+
@perms = perms.to_a
|
52
|
+
case action
|
53
|
+
when :apply: apply
|
54
|
+
when :refresh: refresh
|
55
|
+
when :apply_and_refresh: apply; refresh
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def exists?
|
60
|
+
self.class.grantees(@thing).each do |grantee|
|
61
|
+
return true if @id == grantee.id
|
62
|
+
end
|
63
|
+
false
|
64
|
+
end
|
65
|
+
|
66
|
+
def type
|
67
|
+
@id[/^http:/] ? "Group" : "CanonicalUser"
|
68
|
+
end
|
69
|
+
|
70
|
+
def to_s
|
71
|
+
@name || @id
|
72
|
+
end
|
73
|
+
|
74
|
+
def grant(*permissions)
|
75
|
+
permissions.flatten!
|
76
|
+
old_perms = @perms.dup
|
77
|
+
@perms += permissions
|
78
|
+
@perms.uniq!
|
79
|
+
return true if @perms == old_perms
|
80
|
+
apply
|
81
|
+
end
|
82
|
+
|
83
|
+
def revoke(*permissions)
|
84
|
+
permissions.flatten!
|
85
|
+
old_perms = @perms.dup
|
86
|
+
@perms -= permissions
|
87
|
+
@perms.uniq!
|
88
|
+
return true if @perms == old_perms
|
89
|
+
apply
|
90
|
+
end
|
91
|
+
|
92
|
+
def drop
|
93
|
+
@perms = []
|
94
|
+
apply
|
95
|
+
end
|
96
|
+
|
97
|
+
def refresh
|
98
|
+
@perms = []
|
99
|
+
self.class.grantees(@thing).each do |grantee|
|
100
|
+
if @id == grantee.id
|
101
|
+
@name = grantee.name
|
102
|
+
@perms = grantee.perms
|
103
|
+
return true
|
104
|
+
end
|
105
|
+
end
|
106
|
+
false
|
107
|
+
end
|
108
|
+
|
109
|
+
def apply
|
110
|
+
@perms.uniq!
|
111
|
+
owner, grantees = self.class.owner_and_grantees(@thing)
|
112
|
+
# walk through all the grantees and replace the data for the current one and ...
|
113
|
+
grantees.map! { |grantee| grantee.id == @id ? self : grantee }
|
114
|
+
# ... if this grantee is not known - add this bad boy to a list
|
115
|
+
grantees << self unless grantees.include?(self)
|
116
|
+
# set permissions
|
117
|
+
self.class.put_acl(@thing, owner, grantees)
|
118
|
+
end
|
119
|
+
|
120
|
+
def to_xml
|
121
|
+
id_str = @id[/^http/] ? "<URI>#{@id}</URI>" : "<ID>#{@id}</ID>"
|
122
|
+
grants = ''
|
123
|
+
@perms.each do |perm|
|
124
|
+
grants << "<Grant>" +
|
125
|
+
"<Grantee xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " +
|
126
|
+
"xsi:type=\"#{type}\">#{id_str}</Grantee>" +
|
127
|
+
"<Permission>#{perm}</Permission>" +
|
128
|
+
"</Grant>"
|
129
|
+
end
|
130
|
+
grants
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|