ahoward-helene 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
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