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,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
+