ahoward-helene 0.0.3

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.
Files changed (72) hide show
  1. data/Rakefile +274 -0
  2. data/helene.gemspec +26 -0
  3. data/lib/helene.rb +113 -0
  4. data/lib/helene/attempt.rb +46 -0
  5. data/lib/helene/aws.rb +50 -0
  6. data/lib/helene/config.rb +147 -0
  7. data/lib/helene/content_type.rb +15 -0
  8. data/lib/helene/content_type.yml +661 -0
  9. data/lib/helene/error.rb +12 -0
  10. data/lib/helene/logging.rb +55 -0
  11. data/lib/helene/objectpool.rb +220 -0
  12. data/lib/helene/rails.rb +21 -0
  13. data/lib/helene/rightscale/acf/right_acf_interface.rb +379 -0
  14. data/lib/helene/rightscale/awsbase/benchmark_fix.rb +39 -0
  15. data/lib/helene/rightscale/awsbase/right_awsbase.rb +803 -0
  16. data/lib/helene/rightscale/awsbase/support.rb +111 -0
  17. data/lib/helene/rightscale/ec2/right_ec2.rb +1737 -0
  18. data/lib/helene/rightscale/net_fix.rb +160 -0
  19. data/lib/helene/rightscale/right_aws.rb +71 -0
  20. data/lib/helene/rightscale/right_http_connection.rb +507 -0
  21. data/lib/helene/rightscale/s3/right_s3.rb +1094 -0
  22. data/lib/helene/rightscale/s3/right_s3_interface.rb +1180 -0
  23. data/lib/helene/rightscale/sdb/active_sdb.rb +930 -0
  24. data/lib/helene/rightscale/sdb/right_sdb_interface.rb +696 -0
  25. data/lib/helene/rightscale/sqs/right_sqs.rb +388 -0
  26. data/lib/helene/rightscale/sqs/right_sqs_gen2.rb +286 -0
  27. data/lib/helene/rightscale/sqs/right_sqs_gen2_interface.rb +444 -0
  28. data/lib/helene/rightscale/sqs/right_sqs_interface.rb +596 -0
  29. data/lib/helene/s3.rb +34 -0
  30. data/lib/helene/s3/bucket.rb +379 -0
  31. data/lib/helene/s3/grantee.rb +134 -0
  32. data/lib/helene/s3/key.rb +162 -0
  33. data/lib/helene/s3/owner.rb +16 -0
  34. data/lib/helene/sdb.rb +9 -0
  35. data/lib/helene/sdb/base.rb +1204 -0
  36. data/lib/helene/sdb/base/associations.rb +481 -0
  37. data/lib/helene/sdb/base/attributes.rb +90 -0
  38. data/lib/helene/sdb/base/connection.rb +20 -0
  39. data/lib/helene/sdb/base/error.rb +20 -0
  40. data/lib/helene/sdb/base/hooks.rb +82 -0
  41. data/lib/helene/sdb/base/literal.rb +52 -0
  42. data/lib/helene/sdb/base/logging.rb +23 -0
  43. data/lib/helene/sdb/base/transactions.rb +53 -0
  44. data/lib/helene/sdb/base/type.rb +137 -0
  45. data/lib/helene/sdb/base/types.rb +123 -0
  46. data/lib/helene/sdb/base/validations.rb +256 -0
  47. data/lib/helene/sdb/cast.rb +114 -0
  48. data/lib/helene/sdb/connection.rb +36 -0
  49. data/lib/helene/sdb/error.rb +5 -0
  50. data/lib/helene/sdb/interface.rb +412 -0
  51. data/lib/helene/sdb/sentinel.rb +15 -0
  52. data/lib/helene/sleepcycle.rb +29 -0
  53. data/lib/helene/superhash.rb +297 -0
  54. data/lib/helene/util.rb +132 -0
  55. data/test/auth.rb +31 -0
  56. data/test/helper.rb +98 -0
  57. data/test/integration/begin.rb +0 -0
  58. data/test/integration/ensure.rb +8 -0
  59. data/test/integration/s3/bucket.rb +106 -0
  60. data/test/integration/sdb/associations.rb +45 -0
  61. data/test/integration/sdb/creating.rb +13 -0
  62. data/test/integration/sdb/emptiness.rb +56 -0
  63. data/test/integration/sdb/hooks.rb +19 -0
  64. data/test/integration/sdb/limits.rb +27 -0
  65. data/test/integration/sdb/saving.rb +21 -0
  66. data/test/integration/sdb/selecting.rb +39 -0
  67. data/test/integration/sdb/types.rb +31 -0
  68. data/test/integration/sdb/validations.rb +60 -0
  69. data/test/integration/setup.rb +27 -0
  70. data/test/integration/teardown.rb +21 -0
  71. data/test/loader.rb +39 -0
  72. metadata +139 -0
@@ -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