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,36 @@
1
+ module Helene
2
+ module Sdb
3
+ class << Sdb
4
+ def create_connection(*args)
5
+ options = args.extract_options!.to_options!
6
+
7
+ aws_access_key_id =
8
+ options.delete(:aws_access_key_id) || args.shift || Helene.aws_access_key_id
9
+
10
+ aws_secret_access_key =
11
+ options.delete(:aws_secret_access_key) || args.shift || Helene.aws_secret_access_key
12
+
13
+ # options[:multi_thread] = true unless options.has_key?(:multi_thread)
14
+
15
+ Interface.new(aws_access_key_id, aws_secret_access_key, options)
16
+ end
17
+
18
+ def connections(&block)
19
+ block ? @connections.get(&block) : @connections
20
+ end
21
+
22
+ class ConnectionProxy < BlankSlate
23
+ def method_missing(method, *args, &block)
24
+ Sdb.connections do |connection|
25
+ connection.send(method, *args, &block)
26
+ end
27
+ end
28
+ end
29
+
30
+ def connection
31
+ @connection ||= ConnectionProxy.new
32
+ end
33
+ end
34
+ @connections = ObjectPool.new(:size => 4){ create_connection }
35
+ end
36
+ end
@@ -0,0 +1,5 @@
1
+ module Helene
2
+ module Sdb
3
+ class Error < Helene::Error; end
4
+ end
5
+ end
@@ -0,0 +1,412 @@
1
+ module Helene
2
+ module Sdb
3
+ class Interface < RightAws::RightAwsBase
4
+ include RightAws
5
+
6
+ include RightAwsBaseInterface
7
+
8
+ DEFAULT_HOST = 'sdb.amazonaws.com' unless defined?(DEFAULT_HOST)
9
+ DEFAULT_PORT = 443 unless defined?(DEFAULT_PORT)
10
+ DEFAULT_PROTOCOL = 'https' unless defined?(DEFAULT_PROTOCOL)
11
+ API_VERSION = '2007-11-07' unless defined?(API_VERSION)
12
+ DEFAULT_NIL_REPRESENTATION = 'nil' unless defined?(DEFAULT_NIL_REPRESENTATION)
13
+
14
+ @@bench = AwsBenchmarkingBlock.new
15
+ def self.bench_xml; @@bench.xml; end
16
+ def self.bench_sdb; @@bench.service; end
17
+
18
+ attr_reader :last_query_expression
19
+ attr_reader :nil_rep
20
+ alias_method 'nil_representation', 'nil_rep'
21
+
22
+ def initialize(aws_access_key_id=nil, aws_secret_access_key=nil, params={})
23
+ @nil_rep = params[:nil_representation] ? params[:nil_representation] : DEFAULT_NIL_REPRESENTATION
24
+ params.delete(:nil_representation)
25
+ params[:multi_thread] = true #unless params.has_key?(:multi_thread)
26
+ init({ :name => 'SDB',
27
+ :default_host => ENV['SDB_URL'] ? URI.parse(ENV['SDB_URL']).host : DEFAULT_HOST,
28
+ :default_port => ENV['SDB_URL'] ? URI.parse(ENV['SDB_URL']).port : DEFAULT_PORT,
29
+ :default_protocol => ENV['SDB_URL'] ? URI.parse(ENV['SDB_URL']).scheme : DEFAULT_PROTOCOL },
30
+ aws_access_key_id || ENV['AWS_ACCESS_KEY_ID'],
31
+ aws_secret_access_key || ENV['AWS_SECRET_ACCESS_KEY'],
32
+ params)
33
+ end
34
+
35
+ def generate_request(action, params={}) #:nodoc:
36
+ # remove empty params from request
37
+ params.delete_if {|key,value| value.nil? }
38
+ #params_string = params.to_a.collect{|key,val| key + "=#{CGI::escape(val.to_s)}" }.join("&")
39
+ # prepare service data
40
+ service = '/'
41
+ service_hash = {"Action" => action,
42
+ "AWSAccessKeyId" => @aws_access_key_id,
43
+ "Version" => API_VERSION }
44
+ service_hash.update(params)
45
+ service_params = signed_service_params(@aws_secret_access_key, service_hash, :get, @params[:server], service)
46
+ #
47
+ # use POST method if the length of the query string is too large
48
+ # see http://docs.amazonwebservices.com/AmazonSimpleDB/2007-11-07/DeveloperGuide/MakingRESTRequests.html
49
+ if service_params.size > 2000
50
+ if signature_version == '2'
51
+ # resign the request because HTTP verb is included into signature
52
+ service_params = signed_service_params(@aws_secret_access_key, service_hash, :post, @params[:server], service)
53
+ end
54
+ request = Net::HTTP::Post.new(service)
55
+ request.body = service_params
56
+ request['Content-Type'] = 'application/x-www-form-urlencoded'
57
+ else
58
+ request = Net::HTTP::Get.new("#{service}?#{service_params}")
59
+ end
60
+ # prepare output hash
61
+ { :request => request,
62
+ :server => @params[:server],
63
+ :port => @params[:port],
64
+ :protocol => @params[:protocol] }
65
+ end
66
+
67
+ # TODO - need to dig much deeper into why this sometimes fails in MT
68
+ # conditions
69
+ #
70
+ def request_info(request, parser) #:nodoc:
71
+ #thread = @params[:multi_thread] ? Thread.current : Thread.main
72
+ #thread = Thread.current
73
+ #thread[:sdb_connection] ||= Rightscale::HttpConnection.new(:exception => AwsError, :logger => @logger)
74
+ @connection ||= Rightscale::HttpConnection.new(:exception => AwsError, :logger => @logger)
75
+ e = nil
76
+ # 42.times do
77
+ # begin
78
+ #return request_info_impl(thread[:sdb_connection], @@bench, request, parser)
79
+ return request_info_impl(@connection, @@bench, request, parser)
80
+ # rescue Object => e
81
+ # raise unless e.class <= StandardError
82
+ # @logger.error{ e } rescue nil
83
+ # thread[:sdb_connection] = Rightscale::HttpConnection.new(:exception => AwsError, :logger => @logger)
84
+ # next
85
+ # end
86
+ # end
87
+ raise(e || 'wtf')
88
+ end
89
+
90
+ def escape(value)
91
+ if value
92
+ value = value.to_s.gsub(/(['\\])/){ "\\#{$1}" }
93
+ "'#{ value }'"
94
+ end
95
+ end
96
+
97
+ def ruby_to_sdb(value)
98
+ value.nil? ? @nil_rep : value
99
+ end
100
+
101
+ def sdb_to_ruby(value)
102
+ value.eql?(@nil_rep) ? nil : value
103
+ end
104
+
105
+ def sdb_nil
106
+ unless defined?(@sdb_nil)
107
+ @sdb_nil = ruby_to_sdb(@nil_rep)
108
+ end
109
+ @sdb_nil
110
+ end
111
+
112
+ def ruby_nil
113
+ unless defined?(@ruby_nil)
114
+ @ruby_nil = sdb_to_ruby(sdb_nil)
115
+ end
116
+ @ruby_nil
117
+ end
118
+
119
+ def query_expression_from_array(params) #:nodoc:
120
+ return '' if params.blank?
121
+ query = params.shift.to_s
122
+ query.gsub(/(\\)?(\?)/) do
123
+ if $1 # if escaped '\?' is found - replace it by '?' without backslash
124
+ "?"
125
+ else # well, if no backslash precedes '?' then replace it by next param from the list
126
+ escape(params.shift)
127
+ end
128
+ end
129
+ end
130
+
131
+ def query_expression_from_hash(hash)
132
+ return '' if hash.blank?
133
+ expression = []
134
+ hash.each do |key, value|
135
+ expression << "#{key}=#{escape(value)}"
136
+ end
137
+ expression.join(' AND ')
138
+ end
139
+
140
+ def list_domains(max_number_of_domains = nil, next_token = nil )
141
+ request_params = { 'MaxNumberOfDomains' => max_number_of_domains,
142
+ 'NextToken' => next_token }
143
+ link = generate_request("ListDomains", request_params)
144
+ result = request_info(link, QSdbListDomainParser.new)
145
+ # return result if no block given
146
+ return result unless block_given?
147
+ # loop if block if given
148
+ begin
149
+ # the block must return true if it wanna continue
150
+ break unless yield(result) && result[:next_token]
151
+ # make new request
152
+ request_params['NextToken'] = result[:next_token]
153
+ link = generate_request("ListDomains", request_params)
154
+ result = request_info(link, QSdbListDomainParser.new)
155
+ end while true
156
+ rescue Exception
157
+ on_exception
158
+ end
159
+
160
+ def create_domain(domain_name)
161
+ link = generate_request("CreateDomain",
162
+ 'DomainName' => domain_name)
163
+ request_info(link, QSdbSimpleParser.new)
164
+ rescue Exception
165
+ on_exception
166
+ end
167
+
168
+ def delete_domain(domain_name)
169
+ link = generate_request("DeleteDomain",
170
+ 'DomainName' => domain_name)
171
+ request_info(link, QSdbSimpleParser.new)
172
+ rescue Exception
173
+ on_exception
174
+ end
175
+
176
+ def put_attributes(domain_name, item_name, attributes, replace = false)
177
+ params = { 'DomainName' => domain_name,
178
+ 'ItemName' => item_name }.merge(pack_put_attributes(attributes, :replace => replace))
179
+ link = generate_request("PutAttributes", params)
180
+ request_info( link, QSdbSimpleParser.new )
181
+ rescue Exception
182
+ on_exception
183
+ end
184
+
185
+ def pack_put_attributes(attributes, options)
186
+ replace = (options.delete(:replace) || false)
187
+ prefix = options.delete(:prefix)
188
+
189
+ result = {}
190
+
191
+ if attributes
192
+ idx = 0
193
+ attributes = attributes.inject({}){|h,k| h.update k=>nil} if attributes.is_a?(Array)
194
+ attributes.each do |attribute, value|
195
+ attribute = attribute.to_s
196
+
197
+ if value.is_a?(Array)
198
+ values = Array(value).flatten
199
+
200
+ result["#{prefix}Attribute.#{idx}.Replace"] = 'true' if replace
201
+ result["#{prefix}Attribute.#{idx}.Name"] = attribute
202
+ result["#{prefix}Attribute.#{idx}.Value"] = Sentinel.Set
203
+ idx += 1
204
+
205
+ values.each do |value|
206
+ result["#{prefix}Attribute.#{idx}.Replace"] = 'true' if replace
207
+ result["#{prefix}Attribute.#{idx}.Name"] = attribute
208
+ result["#{prefix}Attribute.#{idx}.Value"] = ruby_to_sdb(value)
209
+ idx += 1
210
+ end
211
+ else
212
+ result["#{prefix}Attribute.#{idx}.Replace"] = 'true' if replace
213
+ result["#{prefix}Attribute.#{idx}.Name"] = attribute
214
+ result["#{prefix}Attribute.#{idx}.Value"] = ruby_to_sdb(value)
215
+ idx += 1
216
+ end
217
+ end
218
+ end
219
+
220
+ result
221
+ end
222
+
223
+ def batch_put_attributes(domain_name, items, replace = false)
224
+ raise ArgumentError if items.empty?
225
+ params = { 'DomainName' => domain_name }.merge(pack_batch_put_attributes(items, :replace => replace))
226
+ link = generate_request("BatchPutAttributes", params)
227
+ request_info( link, QSdbSimpleParser.new )
228
+ rescue Exception
229
+ on_exception
230
+ end
231
+
232
+ def pack_batch_put_attributes(items, options)
233
+ result = {}
234
+ index = -1
235
+ items.each do |item_name, attributes|
236
+ prefix = "Item.#{ index += 1 }."
237
+ result.update pack_put_attributes(attributes, options.merge(:prefix => prefix))
238
+ result.update "#{ prefix }ItemName" => item_name
239
+ end
240
+ result
241
+ end
242
+
243
+ def get_attributes(domain_name, item_name, attribute_name=nil)
244
+ link = generate_request("GetAttributes", 'DomainName' => domain_name,
245
+ 'ItemName' => item_name,
246
+ 'AttributeName' => attribute_name )
247
+ res = request_info(link, QSdbGetAttributesParser.new)
248
+ res[:attributes].each_value do |values|
249
+ values.collect! { |e| sdb_to_ruby(e) }
250
+ end
251
+ res
252
+ rescue Exception
253
+ on_exception
254
+ end
255
+
256
+ def delete_attributes(domain_name, item_name, attributes = {})
257
+ params = { 'DomainName' => domain_name, 'ItemName' => item_name }.merge(pack_delete_attributes(attributes))
258
+ link = generate_request("DeleteAttributes", params)
259
+ request_info( link, QSdbSimpleParser.new )
260
+ rescue Exception
261
+ on_exception
262
+ end
263
+
264
+ def pack_delete_attributes(attributes, options = {})
265
+ result = {}
266
+
267
+ if attributes
268
+ idx = 0
269
+ attributes = attributes.inject({}){|h,k| h.update k=>nil} if attributes.is_a?(Array)
270
+ attributes.each do |attribute, value|
271
+ attribute = attribute.to_s
272
+
273
+ unless value.nil?
274
+ values = Array(value).flatten
275
+ values.delete(Sentinel.Array)
276
+ values.each do |value|
277
+ result["Attribute.#{idx}.Name"] = attribute
278
+ result["Attribute.#{idx}.Value"] = ruby_to_sdb(value)
279
+ idx += 1
280
+ end
281
+ else
282
+ result["Attribute.#{idx}.Name"] = attribute
283
+ idx += 1
284
+ end
285
+ end
286
+ end
287
+
288
+ result
289
+ end
290
+
291
+ def delete_item(domain_name, item_name)
292
+ params = { 'DomainName' => domain_name, 'ItemName' => item_name}
293
+ link = generate_request("DeleteAttributes", params)
294
+ request_info( link, QSdbSimpleParser.new )
295
+ rescue Exception
296
+ on_exception
297
+ end
298
+
299
+ def select(select_expression, next_token = nil)
300
+ select_expression = query_expression_from_array(select_expression) if select_expression.is_a?(Array)
301
+ @last_query_expression = select_expression
302
+ #
303
+ request_params = { 'SelectExpression' => select_expression,
304
+ 'NextToken' => next_token }
305
+ link = generate_request("Select", request_params)
306
+ result = select_response_to_ruby(request_info( link, QSdbSelectParser.new(self) ))
307
+ return result unless block_given?
308
+ # loop if block if given
309
+ begin
310
+ # the block must return true if it wanna continue
311
+ break unless yield(result) && result[:next_token]
312
+ # make new request
313
+ request_params['NextToken'] = result[:next_token]
314
+ link = generate_request("Select", request_params)
315
+ result = select_response_to_ruby(request_info( link, QSdbSelectParser.new(self) ))
316
+ end while true
317
+ rescue Exception
318
+ on_exception
319
+ end
320
+
321
+ def select_response_to_ruby(response) #:nodoc:
322
+ #return response
323
+ response[:items].each_with_index do |item, idx|
324
+ item.each do |key, attributes|
325
+ attributes.keys.each do |name|
326
+ values = attributes[name]
327
+ set = values.delete(Sentinel.Set)
328
+ attributes[name] =
329
+ if set
330
+ values.map{|value| sdb_to_ruby(value)}
331
+ else
332
+ sdb_to_ruby(values.first)
333
+ end
334
+ end
335
+ end
336
+ end
337
+ response
338
+ end
339
+
340
+ class QSdbListDomainParser < RightAWSParser #:nodoc:
341
+ def reset
342
+ @result = { :domains => [] }
343
+ end
344
+ def tagend(name)
345
+ case name
346
+ when 'NextToken' then @result[:next_token] = @text
347
+ when 'DomainName' then @result[:domains] << @text
348
+ when 'BoxUsage' then @result[:box_usage] = @text
349
+ when 'RequestId' then @result[:request_id] = @text
350
+ end
351
+ end
352
+ end
353
+
354
+ class QSdbSimpleParser < RightAWSParser #:nodoc:
355
+ def reset
356
+ @result = {}
357
+ end
358
+ def tagend(name)
359
+ case name
360
+ when 'BoxUsage' then @result[:box_usage] = @text
361
+ when 'RequestId' then @result[:request_id] = @text
362
+ end
363
+ end
364
+ end
365
+
366
+ class QSdbGetAttributesParser < RightAWSParser #:nodoc:
367
+ def reset
368
+ @last_attribute_name = nil
369
+ @result = { :attributes => {} }
370
+ end
371
+ def tagend(name)
372
+ case name
373
+ when 'Name' then @last_attribute_name = @text
374
+ when 'Value' then (@result[:attributes][@last_attribute_name] ||= []) << @text
375
+ when 'BoxUsage' then @result[:box_usage] = @text
376
+ when 'RequestId' then @result[:request_id] = @text
377
+ end
378
+ end
379
+ end
380
+
381
+ class QSdbSelectParser < RightAWSParser #:nodoc:
382
+ attr :interface
383
+ def initialize(interface, *args, &block)
384
+ @interface = interface
385
+ super(*args, &block)
386
+ end
387
+ def reset
388
+ @result = { :items => [] }
389
+ end
390
+ def tagend(name)
391
+ case name
392
+ when 'Name'
393
+ case @xmlpath
394
+ when 'SelectResponse/SelectResult/Item'
395
+ @item = @text
396
+ @result[:items] << { @item => {} }
397
+ when 'SelectResponse/SelectResult/Item/Attribute'
398
+ @attribute = @text
399
+ end
400
+ when 'RequestId' then @result[:request_id] = @text
401
+ when 'BoxUsage' then @result[:box_usage] = @text
402
+ when 'NextToken' then @result[:next_token] = @text
403
+ when 'Value'
404
+ (@result[:items].last[@item][@attribute] ||= []) << @text
405
+ end
406
+ end
407
+ end
408
+
409
+ end
410
+ end
411
+ end
412
+