right_aws 1.4.3 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -72,3 +72,41 @@ Initial release.
72
72
  * r1983, konstantin, 2007-10-25 22:33:00 +0400
73
73
  * Fixed ActiveSupport requirement bug (thanks to Toby)
74
74
  * Fixed HttpConnection logging to stdout bug (thanks to Toby)
75
+
76
+ == 1.4.4
77
+
78
+ * r1999, tve, 2007-11-01 00:07:00 -0700
79
+ * Fixed escaping issue affecting key names in S3 gem
80
+ * Fixed duplicate marker in S3 incremental bucket listing
81
+
82
+ * r2001, konstantin, 2007-11-01 12:03:13 +0300
83
+ * Fixed multiple permissions assignment on Grantee#grant/revoke
84
+ * Fixed new grantee permissions set ingnore (Grantee#apply)
85
+ * S3::Grantee#exists? method added
86
+
87
+ * r2109, konstantin, 2007-11-12 21:49:36 +0300
88
+ * RightAwsBaseInterface: caching implemented.
89
+ (The Ec2 functions are being cached: describe_images, describe_instances,
90
+ describe_security_groups and describe_key_pairs)
91
+
92
+ == 1.4.5
93
+ == 1.4.6
94
+ *r 2619, konstantin, 01-17-08 16:18:36 +0300
95
+ * S3 Location constraints support added.
96
+ * Fixed bug with trailing '/' in the bucket name for 'EU' located buckets
97
+ * Added: S3Interface#bucket_location, S3::Bucket#location
98
+
99
+ == 1.4.7
100
+ *r 2622, konstantin, 01-18-08 13:52:20 +0300
101
+ * Virtual domains doc added
102
+ * S3 Query API fixed to support virtual domains.
103
+
104
+ == 1.4.8
105
+ *r 2650, konstantin, 01-24-08 11:12:00 +0300
106
+ * net_fix.rb moved to right_http_connection
107
+
108
+ == 1.5.0
109
+ *r 2688, konstantin, 02-30-08 15:42:00 +0300
110
+ * SDB support added.
111
+ * RightAws::S3::bucket and RightAws::S3::Bucket.create methods behaviour
112
+ changed: param +create+ is set to +false+ by default.
@@ -9,6 +9,7 @@ lib/awsbase/right_awsbase.rb
9
9
  lib/ec2/right_ec2.rb
10
10
  lib/s3/right_s3.rb
11
11
  lib/s3/right_s3_interface.rb
12
+ lib/sdb/right_sdb_interface.rb
12
13
  lib/sqs/right_sqs.rb
13
14
  lib/sqs/right_sqs_interface.rb
14
15
  test/ec2/test_helper.rb
@@ -16,6 +17,8 @@ test/ec2/test_right_ec2.rb
16
17
  test/s3/test_helper.rb
17
18
  test/s3/test_right_s3.rb
18
19
  test/s3/test_right_s3_stubbed.rb
20
+ test/sdb/test_right_sdb.rb
21
+ test/sdb/test_helper.rb
19
22
  test/sqs/test_helper.rb
20
23
  test/sqs/test_right_sqs.rb
21
24
  test/ts_right_aws.rb
data/README.txt CHANGED
@@ -5,15 +5,16 @@ For information about RightScale, see http://www.rightscale.com
5
5
 
6
6
  == DESCRIPTION:
7
7
 
8
- The RightScale AWS gems have been designed to provide a robust, fast, and secure interface to Amazon EC2, Amazon, S3, and Amazon SQS. These gems have been used in production by RightScale since late 2006 and are being maintained to track enhancements made by Amazon. The RightScale AWS gems comprise:
8
+ The RightScale AWS gems have been designed to provide a robust, fast, and secure interface to Amazon EC2, Amazon S3, Amazon SQS, and Amazon SDB. These gems have been used in production by RightScale since late 2006 and are being maintained to track enhancements made by Amazon. The RightScale AWS gems comprise:
9
9
 
10
10
  - RightAws::Ec2 -- interface to Amazon EC2 (Elastic Compute Cloud)
11
11
  - RightAws::S3 and RightAws::S3Interface -- interface to Amazon S3 (Simple Storage Service)
12
12
  - RightAws::Sqs and RightAws::SqsInterface -- interface to Amazon SQS (Simple Queue Service)
13
+ - RightAws::SdbInterface -- interface to Amazon SDB (SimpleDB)
13
14
 
14
15
  == FEATURES:
15
16
 
16
- - Full programmmatic access to EC2, S3, and SQS.
17
+ - Full programmmatic access to EC2, S3, SQS, and SDB.
17
18
  - Complete error handling: all operations check for errors and report complete
18
19
  error information by raising an AwsError.
19
20
  - Persistent HTTP connections with robust network-level retry layer using
@@ -47,7 +48,7 @@ threads, you may want or need an HTTP connection per thread to enable
47
48
  concurrent requests to AWS. The way this plays out in practice is:
48
49
  1. If you have a non-multithreaded Ruby program, use the non-multithreaded setting.
49
50
  2. If you have a multi-threaded Ruby program, use the multithreaded setting to enable
50
- concurrent requests to S3 (or SQS, or EC2).
51
+ concurrent requests to S3 (or SQS, or SDB, or EC2).
51
52
  3. For running under Mongrel/Rails, use the non-multithreaded setting even though
52
53
  mongrel is multithreaded. This is because only one Rails handler is invoked at
53
54
  time (i.e. it acts like a single-threaded program)
@@ -55,7 +56,7 @@ concurrent requests to AWS. The way this plays out in practice is:
55
56
  Note that due to limitations in the I/O of the Ruby interpreter you
56
57
  may not get the degree of parallelism you may expect with the multi-threaded setting.
57
58
 
58
- By default, EC2/S3/SQS interface instances are created in single-threaded mode. Set
59
+ By default, EC2/S3/SQS/SDB interface instances are created in single-threaded mode. Set
59
60
  "params[:multi_thread]" to "true" in the initialization arguments to use
60
61
  multithreaded mode.
61
62
 
@@ -67,10 +68,26 @@ multithreaded mode.
67
68
  http://developer.amazonwebservices.com/connect/kbcategory.jspa?categoryID=48
68
69
  * For SQS read RightAws::Sqs and consult the Amazon SQS API documentation at
69
70
  http://developer.amazonwebservices.com/connect/kbcategory.jspa?categoryID=31
71
+ * For SDB read RightAws::Sdb and consult the Amazon SDB API documentation at
72
+ http://developer.amazonwebservices.com/connect/kbcategory.jspa?categoryID=141
70
73
 
71
74
  == KNOWN ISSUES:
72
75
 
73
- - Amazon recently (8/07) changed the semantics of the SQS service. A
76
+ - 2/11/08: If you use RightAws in conjunction with attachment_fu, the
77
+ right_aws gem must be included (using the require statement) AFTER
78
+ attachment_fu. If right_aws is loaded before attachment_fu, you'll
79
+ encounter errors similar to:
80
+
81
+ s3.amazonaws.com temporarily unavailable: (wrong number of arguments (5 for 4))
82
+
83
+ or
84
+
85
+ 'incompatible Net::HTTP monkey-patch'
86
+
87
+ This is due to a conflict between the right_http_connection gem and another
88
+ gem required by attachment_fu.
89
+
90
+ - 8/07: Amazon has changed the semantics of the SQS service. A
74
91
  new queue may not be created within 60 seconds of the destruction of any
75
92
  older queue with the same name. Certain methods of RightAws::Sqs and
76
93
  RightAws::SqsInterface will fail with the message:
@@ -91,7 +108,7 @@ sudo gem install
91
108
 
92
109
  == LICENSE:
93
110
 
94
- Copyright (c) 2007 RightScale, Inc.
111
+ Copyright (c) 2007-2008 RightScale, Inc.
95
112
 
96
113
  Permission is hereby granted, free of charge, to any person obtaining
97
114
  a copy of this software and associated documentation files (the
data/Rakefile CHANGED
@@ -18,7 +18,7 @@ Hoe.new('right_aws', RightAws::VERSION::STRING) do |p|
18
18
  p.url = p.paragraphs_of('README.txt', 0).first.split(/\n/)[1..-1]
19
19
  p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
20
20
  p.remote_rdoc_dir = "/right_aws_gem_doc"
21
- p.extra_deps = [['right_http_connection','>= 1.2.0']]
21
+ p.extra_deps = [['right_http_connection','>= 1.2.1']]
22
22
  p.test_globs = testglobs
23
23
  end
24
24
 
@@ -59,4 +59,11 @@ task :testec2 do
59
59
  require 'test/ec2/test_right_ec2.rb'
60
60
  end
61
61
 
62
+ desc "Test just the SDB interface"
63
+ task :testsdb do
64
+ require 'test/test_credentials'
65
+ TestCredentials.get_credentials
66
+ require 'test/sdb/test_right_sdb.rb'
67
+ end
68
+
62
69
  # vim: syntax=Ruby
@@ -23,7 +23,8 @@
23
23
 
24
24
  # Test
25
25
  module RightAws
26
-
26
+ require 'md5'
27
+
27
28
  class AwsUtils #:nodoc:
28
29
  def self.sign(aws_secret_access_key, auth_string)
29
30
  Base64.encode64(OpenSSL::HMAC.digest(OpenSSL::Digest::Digest.new("sha1"), aws_secret_access_key, auth_string)).strip
@@ -41,6 +42,9 @@ module RightAws
41
42
  end
42
43
  end
43
44
 
45
+ class AwsNoChange < RuntimeError
46
+ end
47
+
44
48
  class RightAwsBase
45
49
 
46
50
  # Amazon HTTP Error handling
@@ -70,11 +74,18 @@ module RightAws
70
74
  def self.amazon_problems=(problems_list)
71
75
  @@amazon_problems = problems_list
72
76
  end
73
-
77
+
74
78
  end
75
79
 
76
80
  module RightAwsBaseInterface
77
-
81
+ @@caching = false
82
+ def self.caching
83
+ @@caching
84
+ end
85
+ def self.caching=(caching)
86
+ @@caching = caching
87
+ end
88
+
78
89
  # Current aws_access_key_id
79
90
  attr_reader :aws_access_key_id
80
91
  # Last HTTP request object
@@ -91,6 +102,8 @@ module RightAws
91
102
  attr_accessor :params
92
103
  # RightHttpConnection instance
93
104
  attr_reader :connection
105
+ # Cache
106
+ attr_reader :cache
94
107
 
95
108
  def init(service_info, aws_access_key_id, aws_secret_access_key, params={}) #:nodoc:
96
109
  @params = params
@@ -107,9 +120,51 @@ module RightAws
107
120
  @logger = Logger.new(STDOUT) if !@logger
108
121
  @logger.info "New #{self.class.name} using #{@params[:multi_thread] ? 'multi' : 'single'}-threaded mode"
109
122
  @error_handler = nil
123
+ @cache = {}
110
124
  end
111
125
 
126
+ # Returns +true+ if the describe_xxx responses are being cached
127
+ def caching?
128
+ @params.key?(:cache) ? @params[:cache] : @@caching
129
+ end
130
+
131
+ # Check if the aws function response hits the cache or not.
132
+ # If the cache hits:
133
+ # - raises an +AwsNoChange+ exception if +do_raise+ == +:raise+.
134
+ # - returnes parsed response from the cache if it exists or +true+ otherwise.
135
+ # If the cache miss or the caching is off then returns +false+.
136
+ def cache_hits?(function, response, do_raise=:raise)
137
+ result = false
138
+ if caching?
139
+ function = function.to_sym
140
+ response_md5 = MD5.md5(response).to_s
141
+ # well, the response is new, reset cache data
142
+ unless @cache[function] && @cache[function][:response_md5] == response_md5
143
+ update_cache(function, {:response_md5 => response_md5,
144
+ :timestamp => Time.now,
145
+ :hits => 0,
146
+ :parsed => nil})
147
+ else
148
+ # aha, cache hits, update the data and throw an exception if needed
149
+ @cache[function][:hits] += 1
150
+ if do_raise == :raise
151
+ raise(AwsNoChange, "Cache hit: #{function} response has not changed since "+
152
+ "#{@cache[function][:timestamp].strftime('%Y-%m-%d %H:%M:%S')}, "+
153
+ "hits: #{@cache[function][:hits]}.")
154
+ else
155
+ result = @cache[function][:parsed] || true
156
+ end
157
+ end
158
+ end
159
+ result
160
+ end
161
+
162
+ def update_cache(function, hash)
163
+ (@cache[function.to_sym] ||= {}).merge!(hash) if caching?
164
+ end
165
+
112
166
  def on_exception(options={:raise=>true, :log=>true}) # :nodoc:
167
+ raise if $!.is_a?(AwsNoChange)
113
168
  AwsError::on_aws_exception(self, options)
114
169
  end
115
170
 
@@ -253,7 +308,7 @@ module RightAws
253
308
  # Used to force logging.
254
309
  def self.system_error?(e)
255
310
  !e.is_a?(self) || e.message =~ /InternalError|InsufficientInstanceCapacity|Unavailable/
256
- end
311
+ end
257
312
 
258
313
  end
259
314
 
@@ -316,21 +371,40 @@ module RightAws
316
371
  def check(request) #:nodoc:
317
372
  result = false
318
373
  error_found = false
374
+ redirect_detected= false
319
375
  error_match = nil
320
376
  last_errors_text = ''
321
377
  response = @aws.last_response
322
- # log error
378
+ # log error
323
379
  request_text_data = "#{request[:server]}:#{request[:port]}#{request[:request].path}"
324
- @aws.logger.warn("##### #{@aws.class.name} returned an error: #{response.code} #{response.message}\n#{response.body} #####")
325
- @aws.logger.warn("##### #{@aws.class.name} request: #{request_text_data} ####")
380
+ # is this a redirect?
381
+ # yes!
382
+ if response.is_a?(Net::HTTPRedirection)
383
+ redirect_detected = true
384
+ else
385
+ # no, it's an error ...
386
+ @aws.logger.warn("##### #{@aws.class.name} returned an error: #{response.code} #{response.message}\n#{response.body} #####")
387
+ @aws.logger.warn("##### #{@aws.class.name} request: #{request_text_data} ####")
388
+ end
326
389
  # Check response body: if it is an Amazon XML document or not:
327
- if response.body && response.body[/<\?xml/] # ... it is a xml document
390
+ if redirect_detected || (response.body && response.body[/<\?xml/]) # ... it is a xml document
328
391
  @aws.class.bench_xml.add! do
329
392
  error_parser = RightErrorResponseParser.new
330
393
  error_parser.parse(response)
331
394
  @aws.last_errors = error_parser.errors
332
395
  @aws.last_request_id = error_parser.requestID
333
396
  last_errors_text = @aws.last_errors.flatten.join("\n")
397
+ # on redirect :
398
+ if redirect_detected
399
+ location = response['location']
400
+ # ... log information and ...
401
+ @aws.logger.info("##### #{@aws.class.name} redirect requested: #{response.code} #{response.message} #####")
402
+ @aws.logger.info("##### New location: #{location} #####")
403
+ # ... fix the connection data
404
+ request[:server] = URI.parse(location).host
405
+ request[:protocol] = URI.parse(location).scheme
406
+ request[:port] = URI.parse(location).port
407
+ end
334
408
  end
335
409
  else # ... it is not a xml document(probably just a html page?)
336
410
  @aws.last_errors = [[response.code, "#{response.message} (#{request_text_data})"]]
@@ -338,29 +412,34 @@ module RightAws
338
412
  last_errors_text = response.message
339
413
  end
340
414
  # now - check the error
341
- @errors_list.each do |error_to_find|
342
- if last_errors_text[/#{error_to_find}/i]
343
- error_found = true
344
- error_match = error_to_find
345
- @aws.logger.warn("##### Retry is needed, error pattern match: #{error_to_find} #####")
346
- break
415
+ unless redirect_detected
416
+ @errors_list.each do |error_to_find|
417
+ if last_errors_text[/#{error_to_find}/i]
418
+ error_found = true
419
+ error_match = error_to_find
420
+ @aws.logger.warn("##### Retry is needed, error pattern match: #{error_to_find} #####")
421
+ break
422
+ end
347
423
  end
348
424
  end
349
425
  # check the time has gone from the first error come
350
- if error_found
426
+ if redirect_detected || error_found
351
427
  # Close the connection to the server and recreate a new one.
352
428
  # It may have a chance that one server is a semi-down and reconnection
353
429
  # will help us to connect to the other server
354
- if @close_on_error
430
+ if !redirect_detected && @close_on_error
355
431
  @aws.connection.finish "#{self.class.name}: error match to pattern '#{error_match}'"
356
432
  end
357
433
 
358
434
  if (Time.now < @stop_at)
359
435
  @retries += 1
360
- @aws.logger.warn("##### Retry ##{@retries} is being performed. Sleeping for #{@reiteration_delay} sec. Whole time: #{Time.now-@started_at} sec ####")
361
- sleep @reiteration_delay
362
-
363
- @reiteration_delay *= 2
436
+ unless redirect_detected
437
+ @aws.logger.warn("##### Retry ##{@retries} is being performed. Sleeping for #{@reiteration_delay} sec. Whole time: #{Time.now-@started_at} sec ####")
438
+ sleep @reiteration_delay
439
+ @reiteration_delay *= 2
440
+ else
441
+ @aws.logger.info("##### Retry ##{@retries} is being performed due to a redirect. ####")
442
+ end
364
443
  result = @aws.request_info(request, @parser)
365
444
  else
366
445
  @aws.logger.warn("##### Ooops, time is over... ####")
@@ -516,14 +595,27 @@ module RightAws
516
595
  # PARSERS: Errors
517
596
  #-----------------------------------------------------------------
518
597
 
598
+ #<Error>
599
+ # <Code>TemporaryRedirect</Code>
600
+ # <Message>Please re-send this request to the specified temporary endpoint. Continue to use the original request endpoint for future requests.</Message>
601
+ # <RequestId>FD8D5026D1C5ABA3</RequestId>
602
+ # <Endpoint>bucket-for-k.s3-external-3.amazonaws.com</Endpoint>
603
+ # <HostId>ItJy8xPFPli1fq/JR3DzQd3iDvFCRqi1LTRmunEdM1Uf6ZtW2r2kfGPWhRE1vtaU</HostId>
604
+ # <Bucket>bucket-for-k</Bucket>
605
+ #</Error>
606
+
519
607
  class RightErrorResponseParser < RightAWSParser #:nodoc:
520
608
  attr_accessor :errors # array of hashes: error/message
521
609
  attr_accessor :requestID
610
+ # attr_accessor :endpoint, :host_id, :bucket
522
611
  def tagend(name)
523
612
  case name
524
613
  when 'RequestID' ; @requestID = @text
525
614
  when 'Code' ; @code = @text
526
615
  when 'Message' ; @message = @text
616
+ # when 'Endpoint' ; @endpoint = @text
617
+ # when 'HostId' ; @host_id = @text
618
+ # when 'Bucket' ; @bucket = @text
527
619
  when 'Error' ; @errors << [ @code, @message ]
528
620
  end
529
621
  end
@@ -531,5 +623,5 @@ module RightAws
531
623
  @errors = []
532
624
  end
533
625
  end
534
-
626
+
535
627
  end
@@ -87,6 +87,14 @@ unless defined? ActiveSupport::CoreExtensions
87
87
 
88
88
  class Hash #:nodoc:
89
89
  alias_method :blank?, :empty?
90
+
91
+ # Return a new hash with all keys converted to symbols.
92
+ def symbolize_keys
93
+ inject({}) do |options, (key, value)|
94
+ options[key.to_sym] = value
95
+ options
96
+ end
97
+ end
90
98
  end
91
99
 
92
100
  class String #:nodoc:
@@ -154,19 +154,18 @@ module RightAws
154
154
  #-----------------------------------------------------------------
155
155
  #-----------------------------------------------------------------
156
156
 
157
- def ec2_describe_images(type, list, &block) #:nodoc:
157
+ def ec2_describe_images(type, list) #:nodoc:
158
158
  link = generate_request("DescribeImages", hash_params(type,list.to_a))
159
159
  # We do not want to break the logic of parsing hence will use a dummy parser to process all the standart
160
160
  # steps (errors checking etc). The dummy parser does nothig - just returns back the params it received.
161
- # Then call the block (if it is) with the response. If the block returns +nil+ or +false+ then do not process
162
- # real response parsing and exit with +nil+. Otherwise process parsing and return its result.
161
+ # If the caching is enabled and hit then throw AwsNoChange.
162
+ # P.S. caching works for the whole images list only! (when the list param is blank)
163
163
  response, params = request_info(link, QEc2DummyParser.new)
164
- if block
165
- return nil unless block.call(response)
166
- end
164
+ # if cache is ON and hits then throws AwsNoChange
165
+ cache_hits?(:describe_images, response.body) if list.blank?
167
166
  parser = QEc2DescribeImagesParser.new(:logger => @logger)
168
167
  @@bench.xml.add!{ parser.parse(response, params) }
169
- parser.result.collect do |image|
168
+ result = parser.result.collect do |image|
170
169
  { :aws_id => image.imageId,
171
170
  :aws_location => image.imageLocation,
172
171
  :aws_owner => image.imageOwnerId,
@@ -174,6 +173,9 @@ module RightAws
174
173
  :aws_is_public => image.isPublic,
175
174
  :aws_product_codes => image.productCodes }
176
175
  end
176
+ # put parsed data into cache if the caching is ON
177
+ update_cache(:describe_images, :parsed => result) if list.blank?
178
+ result
177
179
  rescue Exception
178
180
  on_exception
179
181
  end
@@ -198,19 +200,8 @@ module RightAws
198
200
  # :aws_location => "marcins_cool_public_images/ubuntu-6.10.manifest.xml",
199
201
  # :aws_is_public => true}]
200
202
  #
201
- # If a block is given then yields a respose before parsing.
202
- # If the block returns +false+ or +nil+ the response is not parsed
203
- # and describe_images returns +nil+.
204
- #
205
- # images = ec2.describe_images do |response|
206
- # # Compare the response to the previous. If they are the same skip parsing - nothing
207
- # # has changed at Amazon. Skpping the parsing will save us a lots of time for the big
208
- # # responses.
209
- # response.body == previous_response_body ? false : true
210
- # end
211
- #
212
- def describe_images(list=[], &block)
213
- ec2_describe_images('ImageId', list, &block)
203
+ def describe_images(list=[])
204
+ ec2_describe_images('ImageId', list)
214
205
  end
215
206
 
216
207
  #
@@ -219,8 +210,8 @@ module RightAws
219
210
  # ec2.describe_images_by_owner('522821470517')
220
211
  # ec2.describe_images_by_owner('self')
221
212
  #
222
- def describe_images_by_owner(list, &block)
223
- ec2_describe_images('Owner', list, &block)
213
+ def describe_images_by_owner(list)
214
+ ec2_describe_images('Owner', list)
224
215
  end
225
216
 
226
217
  #
@@ -229,8 +220,8 @@ module RightAws
229
220
  # ec2.describe_images_by_executable_by('522821470517')
230
221
  # ec2.describe_images_by_executable_by('self')
231
222
  #
232
- def describe_images_by_executable_by(list, &block)
233
- ec2_describe_images('ExecutableBy', list, &block)
223
+ def describe_images_by_executable_by(list)
224
+ ec2_describe_images('ExecutableBy', list)
234
225
  end
235
226
 
236
227
 
@@ -379,7 +370,8 @@ module RightAws
379
370
  :aws_image_id => instance.imageId,
380
371
  :aws_reason => reason,
381
372
  :aws_product_codes => instance.productCodes,
382
- :aws_instance_type => instance.instanceType}
373
+ :aws_instance_type => instance.instanceType,
374
+ :aws_launch_time => instance.launchTime}
383
375
  end
384
376
  end
385
377
  result
@@ -402,29 +394,21 @@ module RightAws
402
394
  # :ssh_key_name => "staging",
403
395
  # :aws_groups => ["default"],
404
396
  # :private_dns_name => "domU-12-34-67-89-01-C9.usma2.compute.amazonaws.com",
405
- # :aws_instance_type => "m1.small"},
397
+ # :aws_instance_type => "m1.small",
398
+ # :aws_launch_time => "2008-1-1T00:00:00.000Z"},
406
399
  # ..., {...}]
407
400
  #
408
- # If a block is given then yields a respose before parsing.
409
- # If the block returns +false+ or +nil+ the response is not parsed
410
- # and describe_instances returns +nil+.
411
- #
412
- # instances = ec2.describe_instances do |response|
413
- # # Compare the response to the previous. If they are the same skip parsing - nothing
414
- # # has changed at Amazon. Skpping the parsing will save us a lots of time for the big
415
- # # responses.
416
- # response.body == previous_response_body ? false : true
417
- # end
418
- #
419
- def describe_instances(list=[], &block)
401
+ def describe_instances(list=[])
420
402
  link = generate_request("DescribeInstances", hash_params('InstanceId',list.to_a))
421
403
  response, params = request_info(link, QEc2DummyParser.new)
422
- if block
423
- return nil unless block.call(response)
424
- end
404
+ # check cache
405
+ cache_hits?(:describe_instances, response.body) if list.blank?
425
406
  parser = QEc2DescribeInstancesParser.new(:logger => @logger)
426
407
  @@bench.xml.add!{ parser.parse(response, params) }
427
- get_desc_instances(parser.result)
408
+ result = get_desc_instances(parser.result)
409
+ # update parsed data
410
+ update_cache(:describe_instances, :parsed => result) if list.blank?
411
+ result
428
412
  rescue Exception
429
413
  on_exception
430
414
  end
@@ -454,7 +438,8 @@ module RightAws
454
438
  # :ssh_key_name => "my_awesome_key",
455
439
  # :aws_groups => ["my_awesome_group"],
456
440
  # :private_dns_name => "",
457
- # :aws_instance_type => "m1.small"}]
441
+ # :aws_instance_type => "m1.small",
442
+ # :aws_launch_time => "2008-1-1T00:00:00.000Z"}]
458
443
  #
459
444
  def run_instances(image_id, min_count, max_count, group_ids, key_name, user_data='',
460
445
  addressing_type = DEFAULT_ADDRESSING_TYPE,
@@ -493,7 +478,8 @@ module RightAws
493
478
  # :ssh_key_name => "my_awesome_key",
494
479
  # :aws_groups => ["default"],
495
480
  # :private_dns_name => "",
496
- # :aws_instance_type => "m1.small"}]
481
+ # :aws_instance_type => "m1.small",
482
+ # :aws_launch_time => "2008-1-1T00:00:00.000Z"}]
497
483
  #
498
484
  def launch_instances(image_id, lparams={})
499
485
  defaults = {
@@ -606,23 +592,11 @@ module RightAws
606
592
  # {:to_port => "443", :protocol => "tcp", :from_port => "443", :cidr_ips => "0.0.0.0/0"}]},
607
593
  # ..., {...}]
608
594
  #
609
- # If a block is given then yields a respose before parsing.
610
- # If the block returns +false+ or +nil+ the response is not parsed
611
- # and describe_security_groups returns +nil+.
612
- #
613
- # groups = ec2.describe_security_groups do |response|
614
- # # Compare the response to the previous. If they are the same skip parsing - nothing
615
- # # has changed at Amazon. Skpping the parsing will save us a lots of time for the big
616
- # # responses.
617
- # response.body == previous_response_body ? false : true
618
- # end
619
- #
620
- def describe_security_groups(list=[], &block)
595
+ def describe_security_groups(list=[])
621
596
  link = generate_request("DescribeSecurityGroups", hash_params('GroupName',list.to_a))
622
597
  response, params = request_info(link, QEc2DummyParser.new)
623
- if block
624
- return nil unless block.call(response)
625
- end
598
+ # check cache
599
+ cache_hits?(:describe_security_groups, response.body) if list.blank?
626
600
  parser = QEc2DescribeSecurityGroupsParser.new(:logger => @logger)
627
601
  @@bench.xml.add!{ parser.parse(response, params) }
628
602
 
@@ -654,7 +628,9 @@ module RightAws
654
628
  :aws_group_name => item.groupName,
655
629
  :aws_description => item.groupDescription,
656
630
  :aws_perms => perms}
657
- end
631
+ end
632
+ # update parsed data
633
+ update_cache(:describe_security_groups, :parsed => result) if list.blank?
658
634
  result
659
635
  rescue Exception
660
636
  on_exception
@@ -757,29 +733,20 @@ module RightAws
757
733
  # {:aws_fingerprint=> "1e:29:30:47:58:6d:7b:8c:9f:08:11:20:3c:44:52:69:74:80:97:08", :aws_key_name=>"key-2"},
758
734
  # ..., {...} ]
759
735
  #
760
- # If a block is given then yields a respose before parsing.
761
- # If the block returns +false+ or +nil+ the response is not parsed
762
- # and describe_key_pairs returns +nil+.
763
- #
764
- # keys = ec2.describe_key_pairs do |response|
765
- # # Compare the response to the previous. If they are the same skip parsing - nothing
766
- # # has changed at Amazon. Skpping the parsing will save us a lots of time for the big
767
- # # responses.
768
- # response.body == previous_response_body ? false : true
769
- # end
770
- #
771
- def describe_key_pairs(list=[], &block)
736
+ def describe_key_pairs(list=[])
772
737
  link = generate_request("DescribeKeyPairs", hash_params('KeyName',list.to_a))
773
738
  response, params = request_info(link, QEc2DummyParser.new)
774
- if block
775
- return nil unless block.call(response)
776
- end
739
+ # check cache
740
+ cache_hits?(:describe_key_pairs, response.body) if list.blank?
777
741
  parser = QEc2DescribeKeyPairParser.new(:logger => @logger)
778
742
  @@bench.xml.add!{ parser.parse(response, params) }
779
- parser.result.collect do |key|
743
+ result = parser.result.collect do |key|
780
744
  { :aws_key_name => key.keyName,
781
745
  :aws_fingerprint => key.keyFingerprint }
782
746
  end
747
+ # update parsed data
748
+ update_cache(:describe_key_pairs, :parsed => result) if list.blank?
749
+ result
783
750
  rescue Exception
784
751
  on_exception
785
752
  end
@@ -1044,6 +1011,7 @@ module RightAws
1044
1011
  attr_accessor :amiLaunchIndex
1045
1012
  attr_accessor :productCodes
1046
1013
  attr_accessor :instanceType
1014
+ attr_accessor :launchTime
1047
1015
  end
1048
1016
 
1049
1017
  class QEc2DescribeInstancesType #:nodoc:
@@ -1095,6 +1063,7 @@ module RightAws
1095
1063
  end
1096
1064
  when 'productCode' ; (@instance.productCodes ||= []) << @text
1097
1065
  when 'instanceType' ; @instance.instanceType = @text
1066
+ when 'launchTime' ; @instance.launchTime = @text
1098
1067
  end
1099
1068
  end
1100
1069
  def reset
@@ -1150,6 +1119,7 @@ module RightAws
1150
1119
  when 'RunInstancesResponse'; @result << @reservation
1151
1120
  when 'productCode' ; (@instance.productCodes ||= []) << @text
1152
1121
  when 'instanceType' ; @instance.instanceType = @text
1122
+ when 'launchTime' ; @instance.launchTime = @text
1153
1123
  end
1154
1124
  end
1155
1125
  def reset