right_aws 1.10.0 → 2.0.0

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 (39) hide show
  1. data/History.txt +53 -15
  2. data/Manifest.txt +16 -0
  3. data/README.txt +10 -9
  4. data/Rakefile +13 -15
  5. data/lib/acf/right_acf_interface.rb +224 -118
  6. data/lib/acf/right_acf_origin_access_identities.rb +230 -0
  7. data/lib/acf/right_acf_streaming_interface.rb +236 -0
  8. data/lib/acw/right_acw_interface.rb +249 -0
  9. data/lib/as/right_as_interface.rb +699 -0
  10. data/lib/awsbase/right_awsbase.rb +232 -51
  11. data/lib/awsbase/support.rb +4 -0
  12. data/lib/ec2/right_ec2.rb +33 -1375
  13. data/lib/ec2/right_ec2_ebs.rb +452 -0
  14. data/lib/ec2/right_ec2_images.rb +373 -0
  15. data/lib/ec2/right_ec2_instances.rb +755 -0
  16. data/lib/ec2/right_ec2_monitoring.rb +70 -0
  17. data/lib/ec2/right_ec2_reserved_instances.rb +170 -0
  18. data/lib/ec2/right_ec2_security_groups.rb +280 -0
  19. data/lib/ec2/right_ec2_spot_instances.rb +399 -0
  20. data/lib/ec2/right_ec2_vpc.rb +571 -0
  21. data/lib/elb/right_elb_interface.rb +496 -0
  22. data/lib/rds/right_rds_interface.rb +998 -0
  23. data/lib/right_aws.rb +18 -4
  24. data/lib/s3/right_s3.rb +39 -7
  25. data/lib/s3/right_s3_interface.rb +77 -53
  26. data/lib/sdb/active_sdb.rb +203 -11
  27. data/lib/sdb/right_sdb_interface.rb +68 -45
  28. data/lib/sqs/right_sqs_gen2.rb +73 -16
  29. data/lib/sqs/right_sqs_gen2_interface.rb +131 -51
  30. data/lib/sqs/right_sqs_interface.rb +2 -4
  31. data/test/acf/test_right_acf.rb +10 -18
  32. data/test/rds/test_helper.rb +2 -0
  33. data/test/rds/test_right_rds.rb +120 -0
  34. data/test/s3/test_right_s3.rb +10 -8
  35. data/test/s3/test_right_s3_stubbed.rb +6 -4
  36. data/test/sdb/test_active_sdb.rb +70 -12
  37. data/test/sdb/test_right_sdb.rb +13 -7
  38. data/test/sqs/test_right_sqs_gen2.rb +104 -49
  39. metadata +103 -14
@@ -32,6 +32,7 @@ module RightAws
32
32
  DEFAULT_HOST = 'sdb.amazonaws.com'
33
33
  DEFAULT_PORT = 443
34
34
  DEFAULT_PROTOCOL = 'https'
35
+ DEFAULT_PATH = '/'
35
36
  API_VERSION = '2007-11-07'
36
37
  DEFAULT_NIL_REPRESENTATION = 'nil'
37
38
 
@@ -47,7 +48,7 @@ module RightAws
47
48
  # { :server => 'sdb.amazonaws.com' # Amazon service host: 'sdb.amazonaws.com'(default)
48
49
  # :port => 443 # Amazon service port: 80 or 443(default)
49
50
  # :protocol => 'https' # Amazon service protocol: 'http' or 'https'(default)
50
- # :signature_version => '0' # The signature version : '0' or '1'(default)
51
+ # :signature_version => '0' # The signature version : '0','1 or '2'(default)
51
52
  # :multi_thread => true|false # Multi-threaded (connection per each thread): true or false(default)
52
53
  # :logger => Logger Object # Logger instance: logs to STDOUT if omitted
53
54
  # :nil_representation => 'mynil'} # interpret Ruby nil as this string value; i.e. use this string in SDB to represent Ruby nils (default is the string 'nil')
@@ -61,10 +62,12 @@ module RightAws
61
62
  def initialize(aws_access_key_id=nil, aws_secret_access_key=nil, params={})
62
63
  @nil_rep = params[:nil_representation] ? params[:nil_representation] : DEFAULT_NIL_REPRESENTATION
63
64
  params.delete(:nil_representation)
64
- init({ :name => 'SDB',
65
- :default_host => ENV['SDB_URL'] ? URI.parse(ENV['SDB_URL']).host : DEFAULT_HOST,
66
- :default_port => ENV['SDB_URL'] ? URI.parse(ENV['SDB_URL']).port : DEFAULT_PORT,
67
- :default_protocol => ENV['SDB_URL'] ? URI.parse(ENV['SDB_URL']).scheme : DEFAULT_PROTOCOL },
65
+ init({ :name => 'SDB',
66
+ :default_host => ENV['SDB_URL'] ? URI.parse(ENV['SDB_URL']).host : DEFAULT_HOST,
67
+ :default_port => ENV['SDB_URL'] ? URI.parse(ENV['SDB_URL']).port : DEFAULT_PORT,
68
+ :default_service => ENV['SDB_URL'] ? URI.parse(ENV['SDB_URL']).path : DEFAULT_PATH,
69
+ :default_protocol => ENV['SDB_URL'] ? URI.parse(ENV['SDB_URL']).scheme : DEFAULT_PROTOCOL,
70
+ :default_api_version => ENV['SDB_API_VERSION'] || API_VERSION },
68
71
  aws_access_key_id || ENV['AWS_ACCESS_KEY_ID'],
69
72
  aws_secret_access_key || ENV['AWS_SECRET_ACCESS_KEY'],
70
73
  params)
@@ -73,66 +76,55 @@ module RightAws
73
76
  #-----------------------------------------------------------------
74
77
  # Requests
75
78
  #-----------------------------------------------------------------
79
+
76
80
  def generate_request(action, params={}) #:nodoc:
77
- # remove empty params from request
78
- params.delete_if {|key,value| value.nil? }
79
- #params_string = params.to_a.collect{|key,val| key + "=#{CGI::escape(val.to_s)}" }.join("&")
80
- # prepare service data
81
- service = '/'
82
- service_hash = {"Action" => action,
83
- "AWSAccessKeyId" => @aws_access_key_id,
84
- "Version" => API_VERSION }
85
- service_hash.update(params)
86
- service_params = signed_service_params(@aws_secret_access_key, service_hash, :get, @params[:server], service)
87
- #
88
- # use POST method if the length of the query string is too large
89
- # see http://docs.amazonwebservices.com/AmazonSimpleDB/2007-11-07/DeveloperGuide/MakingRESTRequests.html
90
- if service_params.size > 2000
91
- if signature_version == '2'
92
- # resign the request because HTTP verb is included into signature
93
- service_params = signed_service_params(@aws_secret_access_key, service_hash, :post, @params[:server], service)
94
- end
95
- request = Net::HTTP::Post.new(service)
96
- request.body = service_params
97
- request['Content-Type'] = 'application/x-www-form-urlencoded'
98
- else
99
- request = Net::HTTP::Get.new("#{service}?#{service_params}")
100
- end
101
- # prepare output hash
102
- { :request => request,
103
- :server => @params[:server],
104
- :port => @params[:port],
105
- :protocol => @params[:protocol] }
81
+ generate_request_impl(:get, action, params )
106
82
  end
107
83
 
108
84
  # Sends request to Amazon and parses the response
109
85
  # Raises AwsError if any banana happened
110
86
  def request_info(request, parser) #:nodoc:
111
- thread = @params[:multi_thread] ? Thread.current : Thread.main
112
- thread[:sdb_connection] ||= Rightscale::HttpConnection.new(:exception => AwsError, :logger => @logger)
113
- request_info_impl(thread[:sdb_connection], @@bench, request, parser)
87
+ request_info_impl(:sdb_connection, @@bench, request, parser)
114
88
  end
115
89
 
116
90
  # Prepare attributes for putting.
117
91
  # (used by put_attributes)
118
- def pack_attributes(attributes, replace = false) #:nodoc:
92
+ def pack_attributes(items_or_attributes, replace = false, batch = false) #:nodoc:
93
+ if batch
94
+ index = 0
95
+ items_or_attributes.inject({}){|result, (item_name, attributes)|
96
+ item_prefix = "Item.#{index}."
97
+ result["#{item_prefix}ItemName"] = item_name.to_s
98
+ result.merge!(
99
+ pack_single_item_attributes(attributes, replace, item_prefix))
100
+ index += 1
101
+ result
102
+ }
103
+ else
104
+ pack_single_item_attributes(items_or_attributes, replace)
105
+ end
106
+ end
107
+
108
+ def pack_single_item_attributes(attributes, replace, prefix = "")
119
109
  result = {}
120
110
  if attributes
121
111
  idx = 0
122
112
  skip_values = attributes.is_a?(Array)
123
113
  attributes.each do |attribute, values|
124
114
  # set replacement attribute
125
- result["Attribute.#{idx}.Replace"] = 'true' if replace
115
+ result["#{prefix}Attribute.#{idx}.Replace"] = 'true' if replace
126
116
  # pack Name/Value
127
117
  unless values.nil?
128
- Array(values).each do |value|
129
- result["Attribute.#{idx}.Name"] = attribute
130
- result["Attribute.#{idx}.Value"] = ruby_to_sdb(value) unless skip_values
118
+ # Array(values) does not work here:
119
+ # - Array('') => [] but we wanna get here ['']
120
+ [values].flatten.each do |value|
121
+ result["#{prefix}Attribute.#{idx}.Name"] = attribute
122
+ result["#{prefix}Attribute.#{idx}.Value"] = ruby_to_sdb(value) unless skip_values
131
123
  idx += 1
132
124
  end
133
125
  else
134
- result["Attribute.#{idx}.Name"] = attribute
135
- result["Attribute.#{idx}.Value"] = ruby_to_sdb(nil) unless skip_values
126
+ result["#{prefix}Attribute.#{idx}.Name"] = attribute
127
+ result["#{prefix}Attribute.#{idx}.Value"] = ruby_to_sdb(nil) unless skip_values
136
128
  idx += 1
137
129
  end
138
130
  end
@@ -333,6 +325,37 @@ module RightAws
333
325
  rescue Exception
334
326
  on_exception
335
327
  end
328
+
329
+ # Add/Replace attributes for multiple items at a time.
330
+ #
331
+ # Params:
332
+ # domain_name = DomainName
333
+ # items = {
334
+ # 'Item1' => {
335
+ # 'nameA' => [valueA1, valueA2,..., valueAN],
336
+ # ...
337
+ # 'nameB' => [valueB1, valueB2,..., valueBN]
338
+ # },
339
+ # 'Item2' => {
340
+ # 'nameC' => [valueC1, valueC2,..., valueCN],
341
+ # ...
342
+ # 'nameD' => [valueD1, valueD2,..., valueDN]
343
+ # }
344
+ # }
345
+ # replace = :replace | any other value to skip replacement
346
+ #
347
+ # Usage of batch_put_attributes is similar to put_attributes except that
348
+ # instead of supplying an item_name and a hash of attributes, you supply a
349
+ # hash of item names to attributes.
350
+ #
351
+ # See: http://docs.amazonwebservices.com/AmazonSimpleDB/latest/DeveloperGuide/index.html?SDB_API_BatchPutAttributes.html
352
+ def batch_put_attributes(domain_name, items, replace = false)
353
+ params = { 'DomainName' => domain_name }.merge(pack_attributes(items, replace, true))
354
+ link = generate_request("BatchPutAttributes", params)
355
+ request_info( link, QSdbSimpleParser.new)
356
+ rescue Exception
357
+ on_exception
358
+ end
336
359
 
337
360
  # Retrieve SDB item's attribute(s).
338
361
  #
@@ -502,7 +525,7 @@ module RightAws
502
525
  # see: http://docs.amazonwebservices.com/AmazonSimpleDB/2007-11-07/DeveloperGuide/index.html?SDB_API_QueryWithAttributes.html
503
526
  #
504
527
  def query_with_attributes(domain_name, attributes=[], query_expression = nil, max_number_of_items = nil, next_token = nil)
505
- attributes = attributes.to_a
528
+ attributes = Array(attributes)
506
529
  query_expression = query_expression_from_array(query_expression) if query_expression.is_a?(Array)
507
530
  @last_query_expression = query_expression
508
531
  #
@@ -136,7 +136,7 @@ module RightAws
136
136
  # queue.clear() #=> true
137
137
  #
138
138
  def clear()
139
- @sqs.interface.clear_queue(@url)
139
+ @sqs.interface.clear_queue(@url)
140
140
  end
141
141
 
142
142
  # Deletes queue. Any messages in the queue will be permanently lost.
@@ -167,11 +167,10 @@ module RightAws
167
167
  #
168
168
  # queue.receive_messages(2,10) #=> array of messages
169
169
  #
170
- def receive_messages(number_of_messages=1, visibility=nil)
171
- list = @sqs.interface.receive_message(@url, number_of_messages, visibility)
170
+ def receive_messages(number_of_messages=1, visibility=nil, attributes=nil)
171
+ list = @sqs.interface.receive_message(@url, number_of_messages, visibility, attributes)
172
172
  list.map! do |entry|
173
- msg = Message.new(self, entry['MessageId'], entry['ReceiptHandle'],
174
- entry['Body'], visibility)
173
+ msg = Message.new(self, entry['MessageId'], entry['ReceiptHandle'], entry['Body'], visibility, entry['Attributes'])
175
174
  msg.received_at = Time.now
176
175
  msg.receive_checksum = entry['MD5OfBody']
177
176
  msg
@@ -183,8 +182,8 @@ module RightAws
183
182
  #
184
183
  # queue.receive #=> #<RightAws::SqsGen2::Message:0xb7bf0884 ... >
185
184
  #
186
- def receive(visibility=nil)
187
- list = receive_messages(1, visibility)
185
+ def receive(visibility=nil, attributes=nil)
186
+ list = receive_messages(1, visibility, attributes)
188
187
  list.empty? ? nil : list[0]
189
188
  end
190
189
 
@@ -193,12 +192,15 @@ module RightAws
193
192
  #
194
193
  # queue.pop #=> #<RightAws::SqsGen2::Message:0xb7bf0884 ... >
195
194
  #
196
- def pop
197
- list = @sqs.interface.pop_messages(@url, 1)
195
+ # # pop a message with custom attributes
196
+ # m = queue.pop(['SenderId', 'SentTimestamp']) #=> #<RightAws::SqsGen2::Message:0xb7bf1884 ... >
197
+ # m.attributes #=> {"SentTimestamp"=>"1240991906937", "SenderId"=>"800000000005"}
198
+ #
199
+ def pop(attributes=nil)
200
+ list = @sqs.interface.pop_messages(@url, 1, attributes)
198
201
  return nil if list.empty?
199
202
  entry = list[0]
200
- msg = Message.new(self, entry['MessageId'], entry['ReceiptHandle'],
201
- entry['Body'], visibility)
203
+ msg = Message.new(self, entry['MessageId'], entry['ReceiptHandle'], entry['Body'], visibility, entry['Attributes'])
202
204
  msg.received_at = Time.now
203
205
  msg.receive_checksum = entry['MD5OfBody']
204
206
  msg
@@ -241,27 +243,77 @@ module RightAws
241
243
  end
242
244
 
243
245
  # Retrieves queue attributes.
244
- # At this moment Amazon supports +VisibilityTimeout+ and +ApproximateNumberOfMessages+ only.
245
246
  # If the name of attribute is set, returns its value. Otherwise, returns a hash of attributes.
246
247
  #
247
248
  # queue.get_attribute('VisibilityTimeout') #=> {"VisibilityTimeout"=>"45"}
248
249
  #
250
+ # P.S. This guy is deprecated. Use +get_attributes+ instead.
249
251
  def get_attribute(attribute='All')
250
- attributes = @sqs.interface.get_queue_attributes(@url, attribute)
252
+ attributes = get_attributes(attribute)
251
253
  attribute=='All' ? attributes : attributes[attribute]
252
254
  end
255
+
256
+ # Retrieves queue attributes.
257
+ #
258
+ # queue.get_attributes #=>
259
+ # {"ApproximateNumberOfMessages" => "0",
260
+ # "LastModifiedTimestamp" => "1240946032",
261
+ # "CreatedTimestamp" => "1240816887",
262
+ # "VisibilityTimeout" => "30",
263
+ # "Policy" => "{"Version":"2008-10-17","Id":...}"}
264
+ #
265
+ # queue.get_attributes("LastModifiedTimestamp", "VisibilityTimeout") #=>
266
+ # {"LastModifiedTimestamp" => "1240946032",
267
+ # "VisibilityTimeout" => "30"}
268
+ #
269
+ def get_attributes(*attributes)
270
+ @sqs.interface.get_queue_attributes(@url, attributes)
271
+ end
272
+
273
+ # Add permission to the queue.
274
+ #
275
+ # queue.add_permissions('testLabel',['125074342641', '125074342642'],
276
+ # ['SendMessage','SendMessage','ReceiveMessage']) #=> true
277
+ #
278
+ def add_permissions(label, grantees, actions)
279
+ @sqs.interface.add_permissions(@url, label, grantees, actions)
280
+ end
281
+
282
+ # Revoke any permissions in the queue policy that matches the +label+ parameter.
283
+ #
284
+ # sqs.remove_permissions('testLabel') # => true
285
+ #
286
+ def remove_permissions(label)
287
+ @sqs.interface.remove_permissions(@url, label)
288
+ end
289
+
290
+ # Get current permissions set. The set is JSON packed.
291
+ #
292
+ # sqs.get_permissions #=>
293
+ # '{"Version":"2008-10-17","Id":"/826693181925/kd-test-gen-2_5/SQSDefaultPolicy",
294
+ # "Statement":[{"Sid":"kd-perm-04","Effect":"Allow","Principal":{"AWS":"100000000001",
295
+ # "AWS":"100000000001","AWS":"100000000002"},"Action":["SQS:SendMessage","SQS:DeleteMessage",
296
+ # "SQS:ReceiveMessage"],"Resource":"/826693181925/kd-test-gen-2_5"},{"Sid":"kd-perm-03",
297
+ # "Effect":"Allow","Principal":{"AWS":"648772224137"},"Action":"SQS:SendMessage",
298
+ # "Resource":"/826693181925/kd-test-gen-2_5"}]}'
299
+ #
300
+ def get_permissions
301
+ get_attributes('Policy')['Policy']
302
+ end
303
+
253
304
  end
254
305
 
255
306
  class Message
256
- attr_reader :queue, :id, :body, :visibility, :receipt_handle
307
+ attr_reader :queue, :id, :body, :visibility, :receipt_handle, :attributes
257
308
  attr_accessor :sent_at, :received_at, :send_checksum, :receive_checksum
258
309
 
259
- def initialize(queue, id=nil, rh = nil, body=nil, visibility=nil)
310
+ def initialize(queue, id=nil, rh = nil, body=nil, visibility=nil, attributes=nil)
260
311
  @queue = queue
261
312
  @id = id
262
313
  @receipt_handle = rh
263
314
  @body = body
264
315
  @visibility = visibility
316
+ @attributes = attributes
265
317
  @sent_at = nil
266
318
  @received_at = nil
267
319
  @send_checksum = nil
@@ -273,6 +325,12 @@ module RightAws
273
325
  @body
274
326
  end
275
327
 
328
+ # Set message visibility timeout.
329
+ def visibility=(visibility_timeout)
330
+ @queue.sqs.interface.change_message_visibility(@queue.url, @receipt_handle, visibility_timeout)
331
+ @visibility = visibility_timeout
332
+ end
333
+
276
334
  # Removes message from queue.
277
335
  # Returns +true+.
278
336
  def delete
@@ -281,6 +339,5 @@ module RightAws
281
339
 
282
340
  end
283
341
 
284
-
285
342
  end
286
343
  end
@@ -38,7 +38,7 @@ module RightAws
38
38
  class SqsGen2Interface < RightAwsBase
39
39
  include RightAwsBaseInterface
40
40
 
41
- API_VERSION = "2008-01-01"
41
+ API_VERSION = "2009-02-01"
42
42
  DEFAULT_HOST = "queue.amazonaws.com"
43
43
  DEFAULT_PORT = 443
44
44
  DEFAULT_PROTOCOL = 'https'
@@ -72,7 +72,7 @@ module RightAws
72
72
  # {:server => 'queue.amazonaws.com' # Amazon service host: 'queue.amazonaws.com' (default)
73
73
  # :port => 443 # Amazon service port: 80 or 443 (default)
74
74
  # :multi_thread => true|false # Multi-threaded (connection per each thread): true or false (default)
75
- # :signature_version => '0' # The signature version : '0' or '1'(default)
75
+ # :signature_version => '0' # The signature version : '0', '1' or '2'(default)
76
76
  # :logger => Logger Object} # Logger instance: logs to STDOUT if omitted }
77
77
  #
78
78
  def initialize(aws_access_key_id=nil, aws_secret_access_key=nil, params={})
@@ -127,7 +127,7 @@ module RightAws
127
127
  #
128
128
  service_params = signed_service_params(@aws_secret_access_key, service_hash, :post, @params[:server], service)
129
129
  request = Net::HTTP::Post.new(AwsUtils::URLencode(service))
130
- request['Content-Type'] = 'application/x-www-form-urlencoded'
130
+ request['Content-Type'] = 'application/x-www-form-urlencoded; charset=utf-8'
131
131
  request.body = service_params
132
132
  # prepare output hash
133
133
  { :request => request,
@@ -140,15 +140,12 @@ module RightAws
140
140
  # Sends request to Amazon and parses the response
141
141
  # Raises AwsError if any banana happened
142
142
  def request_info(request, parser) # :nodoc:
143
- thread = @params[:multi_thread] ? Thread.current : Thread.main
144
- thread[:sqs_connection] ||= Rightscale::HttpConnection.new(:exception => AwsError, :logger => @logger)
145
- request_info_impl(thread[:sqs_connection], @@bench, request, parser)
143
+ request_info_impl(:sqs_connection, @@bench, request, parser)
146
144
  end
147
145
 
148
-
149
146
  # Creates a new queue, returning its URI.
150
147
  #
151
- # sqs.create_queue('my_awesome_queue') #=> 'http://queue.amazonaws.com/ZZ7XXXYYYBINS/my_awesome_queue'
148
+ # sqs.create_queue('my_awesome_queue') #=> 'https://queue.amazonaws.com/ZZ7XXXYYYBINS/my_awesome_queue'
152
149
  #
153
150
  def create_queue(queue_name, default_visibility_timeout=nil)
154
151
  req_hash = generate_request('CreateQueue', 'QueueName' => queue_name,
@@ -164,7 +161,7 @@ module RightAws
164
161
  #
165
162
  # sqs.create_queue('my_awesome_queue')
166
163
  # sqs.create_queue('my_awesome_queue_2')
167
- # sqs.list_queues('my_awesome') #=> ['http://queue.amazonaws.com/ZZ7XXXYYYBINS/my_awesome_queue','http://queue.amazonaws.com/ZZ7XXXYYYBINS/my_awesome_queue_2']
164
+ # sqs.list_queues('my_awesome') #=> ['https://queue.amazonaws.com/ZZ7XXXYYYBINS/my_awesome_queue','https://queue.amazonaws.com/ZZ7XXXYYYBINS/my_awesome_queue_2']
168
165
  #
169
166
  def list_queues(queue_name_prefix=nil)
170
167
  req_hash = generate_request('ListQueues', 'QueueNamePrefix' => queue_name_prefix)
@@ -179,11 +176,10 @@ module RightAws
179
176
  # may still show the deleted queue. It is not unusual within the 60 s window to see the deleted queue absent from
180
177
  # one list_queues call but present in the subsequent one. Deletion is eventual.
181
178
  #
182
- # sqs.delete_queue('http://queue.amazonaws.com/ZZ7XXXYYYBINS/my_awesome_queue_2') #=> true
183
- #
179
+ # sqs.delete_queue('https://queue.amazonaws.com/ZZ7XXXYYYBINS/my_awesome_queue_2') #=> true
184
180
  #
185
181
  def delete_queue(queue_url)
186
- req_hash = generate_request('DeleteQueue', :queue_url => queue_url)
182
+ req_hash = generate_request('DeleteQueue', :queue_url => queue_url)
187
183
  request_info(req_hash, SqsStatusParser.new(:logger => @logger))
188
184
  rescue
189
185
  on_exception
@@ -191,11 +187,24 @@ module RightAws
191
187
 
192
188
  # Retrieves the queue attribute(s). Returns a hash of attribute(s) or an exception.
193
189
  #
194
- # sqs.get_queue_attributes('http://queue.amazonaws.com/ZZ7XXXYYYBINS/my_awesome_queue')
195
- # #=> {"ApproximateNumberOfMessages"=>"0", "VisibilityTimeout"=>"30"}
196
- #
197
- def get_queue_attributes(queue_url, attribute='All')
198
- req_hash = generate_request('GetQueueAttributes', 'AttributeName' => attribute, :queue_url => queue_url)
190
+ # sqs.get_queue_attributes('https://queue.amazonaws.com/ZZ7XXXYYYBINS/my_awesome_queue') #=>
191
+ # {"ApproximateNumberOfMessages" => "0",
192
+ # "LastModifiedTimestamp" => "1240946032",
193
+ # "CreatedTimestamp" => "1240816887",
194
+ # "VisibilityTimeout" => "30",
195
+ # "Policy" => "{"Version":"2008-10-17","Id":...}"}
196
+ #
197
+ # queue.get_queue_attributes('https://queue.amazonaws.com/ZZ7XXXYYYBINS/my_awesome_queue', "LastModifiedTimestamp", "VisibilityTimeout") #=>
198
+ # {"LastModifiedTimestamp" => "1240946032",
199
+ # "VisibilityTimeout" => "30"}
200
+ #
201
+ # http://docs.amazonwebservices.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/index.html?Query_QueryGetQueueAttributes.html
202
+ def get_queue_attributes(queue_url, *attributes)
203
+ attributes.flatten!
204
+ attributes << 'All' if attributes.blank?
205
+ params = amazonize_list('AttributeName', attributes)
206
+ params.merge!(:queue_url => queue_url)
207
+ req_hash = generate_request('GetQueueAttributes', params)
199
208
  request_info(req_hash, SqsGetQueueAttributesParser.new(:logger => @logger))
200
209
  rescue
201
210
  on_exception
@@ -203,48 +212,108 @@ module RightAws
203
212
 
204
213
  # Sets queue attribute. Returns +true+ or an exception.
205
214
  #
206
- # sqs.set_queue_attributes('http://queue.amazonaws.com/ZZ7XXXYYYBINS/my_awesome_queue', "VisibilityTimeout", 10) #=> true
215
+ # sqs.set_queue_attributes('https://queue.amazonaws.com/ZZ7XXXYYYBINS/my_awesome_queue', "VisibilityTimeout", 10) #=> true
207
216
  #
208
217
  # From the SQS Dev Guide:
209
- # "Currently, you can set only the
210
- # VisibilityTimeout attribute for a queue...
211
- # When you change a queue's attributes, the change can take up to 60 seconds to propagate
218
+ # "When you change a queue's attributes, the change can take up to 60 seconds to propagate
212
219
  # throughout the SQS system."
213
220
  #
214
221
  # NB: Attribute values may not be immediately available to other queries
215
222
  # for some time after an update. See the SQS documentation for
216
223
  # semantics, but in general propagation can take up to 60 s.
224
+ #
225
+ # see http://docs.amazonwebservices.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/index.html?Query_QuerySetQueueAttributes.html
217
226
  def set_queue_attributes(queue_url, attribute, value)
218
- req_hash = generate_request('SetQueueAttributes', 'Attribute.Name' => attribute, 'Attribute.Value' => value, :queue_url => queue_url)
227
+ req_hash = generate_request('SetQueueAttributes',
228
+ 'Attribute.Name' => attribute,
229
+ 'Attribute.Value' => value,
230
+ :queue_url => queue_url)
231
+ request_info(req_hash, SqsStatusParser.new(:logger => @logger))
232
+ rescue
233
+ on_exception
234
+ end
235
+
236
+ # Add permissions to a queue.
237
+ #
238
+ # sqs.add_permissions('https://queue.amazonaws.com/ZZ7XXXYYYBINS/my_awesome_queue',
239
+ # 'testLabel', ['125074342641','125074342642'],
240
+ # ['SendMessage','SendMessage','ReceiveMessage']) #=> true
241
+ #
242
+ # +permissions+ is a hash of: AccountId => ActionName
243
+ # (valid ActionNames: * | SendMessage | ReceiveMessage | DeleteMessage | ChangeMessageVisibility | GetQueueAttributes )
244
+ #
245
+ # see http://docs.amazonwebservices.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/index.html?Query_QueryAddPermission.html
246
+ # http://docs.amazonwebservices.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/index.html?acp-overview.html
247
+ def add_permissions(queue_url, label, grantees, actions)
248
+ params = amazonize_list('AWSAccountId', Array(grantees))
249
+ params.merge!(amazonize_list('ActionName', Array(actions)))
250
+ params.merge!('Label' => label,
251
+ :queue_url => queue_url )
252
+ req_hash = generate_request('AddPermission', params)
253
+ request_info(req_hash, SqsStatusParser.new(:logger => @logger))
254
+ rescue
255
+ on_exception
256
+ end
257
+
258
+ # Revoke any permissions in the queue policy that matches the +label+ parameter.
259
+ #
260
+ # sqs.remove_permissions('https://queue.amazonaws.com/ZZ7XXXYYYBINS/my_awesome_queue',
261
+ # 'testLabel') # => true
262
+ #
263
+ # see http://docs.amazonwebservices.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/index.html?Query_QueryRemovePermission.html
264
+ def remove_permissions(queue_url, label)
265
+ req_hash = generate_request('RemovePermission',
266
+ 'Label' => label,
267
+ :queue_url => queue_url )
219
268
  request_info(req_hash, SqsStatusParser.new(:logger => @logger))
220
269
  rescue
221
270
  on_exception
222
271
  end
223
272
 
224
- # Retrieves a list of messages from queue. Returns an array of hashes in format: <tt>{:id=>'message_id', body=>'message_body'}</tt>
273
+ # Retrieves a list of messages from queue. Returns an array of hashes in format: <tt>{:id=>'message_id', :body=>'message_body'}</tt>
225
274
  #
226
- # sqs.receive_message('http://queue.amazonaws.com/ZZ7XXXYYYBINS/my_awesome_queue',10, 5) #=>
275
+ # sqs.receive_message('https://queue.amazonaws.com/ZZ7XXXYYYBINS/my_awesome_queue',10, 5) #=>
227
276
  # [{"ReceiptHandle"=>"Euvo62...kw==", "MD5OfBody"=>"16af2171b5b83cfa35ce254966ba81e3",
228
277
  # "Body"=>"Goodbyte World!", "MessageId"=>"MUM4WlAyR...pYOTA="}, ..., {}]
229
278
  #
230
279
  # Normally this call returns fewer messages than the maximum specified,
231
280
  # even if they are available.
232
281
  #
233
- def receive_message(queue_url, max_number_of_messages=1, visibility_timeout=nil)
282
+ def receive_message(queue_url, max_number_of_messages=1, visibility_timeout=nil, attributes=nil)
234
283
  return [] if max_number_of_messages == 0
235
- req_hash = generate_post_request('ReceiveMessage', 'MaxNumberOfMessages' => max_number_of_messages, 'VisibilityTimeout' => visibility_timeout,
236
- :queue_url => queue_url )
284
+ params = {}
285
+ params.merge!(amazonize_list('AttributeName', Array(attributes))) unless attributes.blank?
286
+ params.merge!('MaxNumberOfMessages' => max_number_of_messages,
287
+ 'VisibilityTimeout' => visibility_timeout,
288
+ :queue_url => queue_url )
289
+ req_hash = generate_post_request('ReceiveMessage', params)
237
290
  request_info(req_hash, SqsReceiveMessageParser.new(:logger => @logger))
238
291
  rescue
239
292
  on_exception
240
293
  end
294
+
295
+ # Change the visibility timeout of a specified message in a queue.
296
+ #
297
+ # sqs.change_message_visibility('https://queue.amazonaws.com/ZZ7XXXYYYBINS/my_awesome_queue', 'Euvo62...kw==', 33) #=> true
298
+ #
299
+ # see http://docs.amazonwebservices.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/index.html?Query_QueryChangeMessageVisibility.html
300
+ def change_message_visibility(queue_url, receipt_handle, visibility_timeout)
301
+ req_hash = generate_request('ChangeMessageVisibility',
302
+ 'ReceiptHandle' => receipt_handle,
303
+ 'VisibilityTimeout' => visibility_timeout,
304
+ :queue_url => queue_url )
305
+ request_info(req_hash, SqsStatusParser.new(:logger => @logger))
306
+ rescue
307
+ on_exception
308
+ end
241
309
 
242
310
  # Sends a new message to a queue. Message size is limited to 8 KB.
243
311
  # If successful, this call returns a hash containing key/value pairs for
244
312
  # "MessageId" and "MD5OfMessageBody":
245
313
  #
246
- # sqs.send_message('http://queue.amazonaws.com/ZZ7XXXYYYBINS/my_awesome_queue', 'message_1') #=> "1234567890...0987654321"
247
- # => {"MessageId"=>"MEs4M0JKNlRCRTBBSENaMjROTk58QVFRNzNEREhDVFlFOVJDQ1JKNjF8UTdBRllCUlJUMjhKMUI1WDJSWDE=", "MD5OfMessageBody"=>"16af2171b5b83cfa35ce254966ba81e3"}
314
+ # sqs.send_message('https://queue.amazonaws.com/ZZ7XXXYYYBINS/my_awesome_queue', 'message_1') #=>
315
+ # {"MessageId"=>"MEs4M0JKNlRCRTBBSENaMjROTk58QVFRNzNEREhDVFlFOVJDQ1JKNjF8UTdBRllCUlJUMjhKMUI1WDJSWDE=",
316
+ # "MD5OfMessageBody"=>"16af2171b5b83cfa35ce254966ba81e3"}
248
317
  #
249
318
  # On failure, send_message raises an exception.
250
319
  #
@@ -271,7 +340,7 @@ module RightAws
271
340
  # you again on a subsequent receive request. You should create your system to be
272
341
  # idempotent so that receiving a particular message more than once is not a problem. "
273
342
  #
274
- # sqs.delete_message('http://queue.amazonaws.com/ZZ7XXXYYYBINS/my_awesome_queue', 'Euvo62/1nlIet...ao03hd9Sa0w==') #=> true
343
+ # sqs.delete_message('https://queue.amazonaws.com/ZZ7XXXYYYBINS/my_awesome_queue', 'Euvo62/1nlIet...ao03hd9Sa0w==') #=> true
275
344
  #
276
345
  def delete_message(queue_url, receipt_handle)
277
346
  req_hash = generate_request('DeleteMessage', 'ReceiptHandle' => receipt_handle, :queue_url => queue_url)
@@ -281,7 +350,7 @@ module RightAws
281
350
  end
282
351
 
283
352
  # Given the queue's short name, this call returns the queue URL or +nil+ if queue is not found
284
- # sqs.queue_url_by_name('my_awesome_queue') #=> 'http://queue.amazonaws.com/ZZ7XXXYYYBINS/my_awesome_queue'
353
+ # sqs.queue_url_by_name('my_awesome_queue') #=> 'https://queue.amazonaws.com/ZZ7XXXYYYBINS/my_awesome_queue'
285
354
  #
286
355
  def queue_url_by_name(queue_name)
287
356
  return queue_name if queue_name.include?('/')
@@ -296,7 +365,7 @@ module RightAws
296
365
 
297
366
  # Returns short queue name by url.
298
367
  #
299
- # RightSqs.queue_name_by_url('http://queue.amazonaws.com/ZZ7XXXYYYBINS/my_awesome_queue') #=> 'my_awesome_queue'
368
+ # RightSqs.queue_name_by_url('https://queue.amazonaws.com/ZZ7XXXYYYBINS/my_awesome_queue') #=> 'my_awesome_queue'
300
369
  #
301
370
  def self.queue_name_by_url(queue_url)
302
371
  queue_url[/[^\/]*$/]
@@ -306,7 +375,7 @@ module RightAws
306
375
 
307
376
  # Returns short queue name by url.
308
377
  #
309
- # sqs.queue_name_by_url('http://queue.amazonaws.com/ZZ7XXXYYYBINS/my_awesome_queue') #=> 'my_awesome_queue'
378
+ # sqs.queue_name_by_url('https://queue.amazonaws.com/ZZ7XXXYYYBINS/my_awesome_queue') #=> 'my_awesome_queue'
310
379
  #
311
380
  def queue_name_by_url(queue_url)
312
381
  self.class.queue_name_by_url(queue_url)
@@ -316,17 +385,19 @@ module RightAws
316
385
 
317
386
  # Returns approximate number of messages in queue.
318
387
  #
319
- # sqs.get_queue_length('http://queue.amazonaws.com/ZZ7XXXYYYBINS/my_awesome_queue') #=> 3
388
+ # sqs.get_queue_length('https://queue.amazonaws.com/ZZ7XXXYYYBINS/my_awesome_queue') #=> 3
320
389
  #
321
390
  def get_queue_length(queue_url)
322
- get_queue_attributes(queue_url)['ApproximateNumberOfMessages'].to_i
391
+ attrs = get_queue_attributes(queue_url)
392
+ attrs['ApproximateNumberOfMessages'].to_i +
393
+ attrs['ApproximateNumberOfMessagesNotVisible'].to_i
323
394
  rescue
324
395
  on_exception
325
396
  end
326
397
 
327
398
  # Removes all visible messages from queue. Return +true+ or an exception.
328
399
  #
329
- # sqs.clear_queue('http://queue.amazonaws.com/ZZ7XXXYYYBINS/my_awesome_queue') #=> true
400
+ # sqs.clear_queue('https://queue.amazonaws.com/ZZ7XXXYYYBINS/my_awesome_queue') #=> true
330
401
  #
331
402
  def clear_queue(queue_url)
332
403
  while (pop_messages(queue_url, 10).length > 0) ; end # delete all messages in queue
@@ -337,12 +408,12 @@ module RightAws
337
408
 
338
409
  # Pops (retrieves and deletes) up to 'number_of_messages' from queue. Returns an array of retrieved messages in format: <tt>[{:id=>'message_id', :body=>'message_body'}]</tt>.
339
410
  #
340
- # sqs.pop_messages('http://queue.amazonaws.com/ZZ7XXXYYYBINS/my_awesome_queue', 3) #=>
411
+ # sqs.pop_messages('https://queue.amazonaws.com/ZZ7XXXYYYBINS/my_awesome_queue', 3) #=>
341
412
  # [{"ReceiptHandle"=>"Euvo62/...+Zw==", "MD5OfBody"=>"16af2...81e3", "Body"=>"Goodbyte World!",
342
413
  # "MessageId"=>"MEZI...JSWDE="}, {...}, ... , {...} ]
343
414
  #
344
- def pop_messages(queue_url, number_of_messages=1)
345
- messages = receive_message(queue_url, number_of_messages)
415
+ def pop_messages(queue_url, number_of_messages=1, attributes=nil)
416
+ messages = receive_message(queue_url, number_of_messages, nil, attributes)
346
417
  messages.each do |message|
347
418
  delete_message(queue_url, message['ReceiptHandle'])
348
419
  end
@@ -353,11 +424,11 @@ module RightAws
353
424
 
354
425
  # Pops (retrieves and deletes) first accessible message from queue. Returns the message in format <tt>{:id=>'message_id', :body=>'message_body'}</tt> or +nil+.
355
426
  #
356
- # sqs.pop_message('http://queue.amazonaws.com/ZZ7XXXYYYBINS/my_awesome_queue') #=>
427
+ # sqs.pop_message('https://queue.amazonaws.com/ZZ7XXXYYYBINS/my_awesome_queue') #=>
357
428
  # {:id=>"12345678904GEZX9746N|0N9ED344VK5Z3SV1DTM0|1RVYH4X3TJ0987654321", :body=>"message_1"}
358
429
  #
359
- def pop_message(queue_url)
360
- messages = pop_messages(queue_url)
430
+ def pop_message(queue_url, attributes=nil)
431
+ messages = pop_messages(queue_url, 1, attributes)
361
432
  messages.blank? ? nil : messages[0]
362
433
  rescue
363
434
  on_exception
@@ -400,8 +471,8 @@ module RightAws
400
471
  end
401
472
  def tagend(name)
402
473
  case name
403
- when 'Name' ; @current_attribute = @text
404
- when 'Value' ; @result[@current_attribute] = @text
474
+ when 'Name' then @current_attribute = @text
475
+ when 'Value' then @result[@current_attribute] = @text
405
476
  end
406
477
  end
407
478
  end
@@ -415,14 +486,23 @@ module RightAws
415
486
  @result = []
416
487
  end
417
488
  def tagstart(name, attributes)
418
- @current_message = {} if name == 'Message'
489
+ case name
490
+ when 'Message' then @current_message = { }
491
+ when 'Attribute' then
492
+ @current_message['Attributes'] ||= {}
493
+ @current_attribute_name = ''
494
+ @current_attribute_value = ''
495
+ end
419
496
  end
420
497
  def tagend(name)
421
498
  case name
422
- when 'MessageId' ; @current_message['MessageId'] = @text
423
- when 'ReceiptHandle' ; @current_message['ReceiptHandle'] = @text
424
- when 'MD5OfBody' ; @current_message['MD5OfBody'] = @text
425
- when 'Body'; @current_message['Body'] = @text; @result << @current_message
499
+ when 'MessageId' then @current_message['MessageId'] = @text
500
+ when 'ReceiptHandle' then @current_message['ReceiptHandle'] = @text
501
+ when 'MD5OfBody' then @current_message['MD5OfBody'] = @text
502
+ when 'Name' then @current_attribute_name = @text
503
+ when 'Value' then @current_attribute_value = @text
504
+ when 'Attribute' then @current_message['Attributes'][@current_attribute_name] = @current_attribute_value
505
+ when 'Body' then @current_message['Body'] = @text; @result << @current_message
426
506
  end
427
507
  end
428
508
  end
@@ -433,8 +513,8 @@ module RightAws
433
513
  end
434
514
  def tagend(name)
435
515
  case name
436
- when 'MessageId' ; @result['MessageId'] = @text
437
- when 'MD5OfMessageBody' ; @result['MD5OfMessageBody'] = @text
516
+ when 'MessageId' then @result['MessageId'] = @text
517
+ when 'MD5OfMessageBody' then @result['MD5OfMessageBody'] = @text
438
518
  end
439
519
  end
440
520
  end