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.
- data/History.txt +53 -15
- data/Manifest.txt +16 -0
- data/README.txt +10 -9
- data/Rakefile +13 -15
- data/lib/acf/right_acf_interface.rb +224 -118
- data/lib/acf/right_acf_origin_access_identities.rb +230 -0
- data/lib/acf/right_acf_streaming_interface.rb +236 -0
- data/lib/acw/right_acw_interface.rb +249 -0
- data/lib/as/right_as_interface.rb +699 -0
- data/lib/awsbase/right_awsbase.rb +232 -51
- data/lib/awsbase/support.rb +4 -0
- data/lib/ec2/right_ec2.rb +33 -1375
- data/lib/ec2/right_ec2_ebs.rb +452 -0
- data/lib/ec2/right_ec2_images.rb +373 -0
- data/lib/ec2/right_ec2_instances.rb +755 -0
- data/lib/ec2/right_ec2_monitoring.rb +70 -0
- data/lib/ec2/right_ec2_reserved_instances.rb +170 -0
- data/lib/ec2/right_ec2_security_groups.rb +280 -0
- data/lib/ec2/right_ec2_spot_instances.rb +399 -0
- data/lib/ec2/right_ec2_vpc.rb +571 -0
- data/lib/elb/right_elb_interface.rb +496 -0
- data/lib/rds/right_rds_interface.rb +998 -0
- data/lib/right_aws.rb +18 -4
- data/lib/s3/right_s3.rb +39 -7
- data/lib/s3/right_s3_interface.rb +77 -53
- data/lib/sdb/active_sdb.rb +203 -11
- data/lib/sdb/right_sdb_interface.rb +68 -45
- data/lib/sqs/right_sqs_gen2.rb +73 -16
- data/lib/sqs/right_sqs_gen2_interface.rb +131 -51
- data/lib/sqs/right_sqs_interface.rb +2 -4
- data/test/acf/test_right_acf.rb +10 -18
- data/test/rds/test_helper.rb +2 -0
- data/test/rds/test_right_rds.rb +120 -0
- data/test/s3/test_right_s3.rb +10 -8
- data/test/s3/test_right_s3_stubbed.rb +6 -4
- data/test/sdb/test_active_sdb.rb +70 -12
- data/test/sdb/test_right_sdb.rb +13 -7
- data/test/sqs/test_right_sqs_gen2.rb +104 -49
- metadata +103 -14
@@ -23,7 +23,8 @@
|
|
23
23
|
|
24
24
|
# Test
|
25
25
|
module RightAws
|
26
|
-
require 'md5'
|
26
|
+
# require 'md5'
|
27
|
+
require 'digest/md5'
|
27
28
|
require 'pp'
|
28
29
|
|
29
30
|
class AwsUtils #:nodoc:
|
@@ -32,6 +33,13 @@ module RightAws
|
|
32
33
|
if OpenSSL::OPENSSL_VERSION_NUMBER > 0x00908000
|
33
34
|
@@digest256 = OpenSSL::Digest::Digest.new("sha256") rescue nil # Some installation may not support sha256
|
34
35
|
end
|
36
|
+
|
37
|
+
def self.utc_iso8601(time)
|
38
|
+
if time.is_a?(Fixnum) then time = Time::at(time)
|
39
|
+
elsif time.is_a?(String) then time = Time::parse(time)
|
40
|
+
end
|
41
|
+
time.utc.strftime("%Y-%m-%dT%H:%M:%S.000Z")
|
42
|
+
end
|
35
43
|
|
36
44
|
def self.sign(aws_secret_access_key, auth_string)
|
37
45
|
Base64.encode64(OpenSSL::HMAC.digest(@@digest1, aws_secret_access_key, auth_string)).strip
|
@@ -47,7 +55,7 @@ module RightAws
|
|
47
55
|
|
48
56
|
# Set a timestamp and a signature version
|
49
57
|
def self.fix_service_params(service_hash, signature)
|
50
|
-
service_hash["Timestamp"] ||= Time.now
|
58
|
+
service_hash["Timestamp"] ||= utc_iso8601(Time.now) unless service_hash["Expires"]
|
51
59
|
service_hash["SignatureVersion"] = signature
|
52
60
|
service_hash
|
53
61
|
end
|
@@ -123,6 +131,11 @@ module RightAws
|
|
123
131
|
$1
|
124
132
|
end
|
125
133
|
|
134
|
+
def self.split_items_and_params(array)
|
135
|
+
items = Array(array).flatten.compact
|
136
|
+
params = items.last.kind_of?(Hash) ? items.pop : {}
|
137
|
+
[items, params]
|
138
|
+
end
|
126
139
|
end
|
127
140
|
|
128
141
|
class AwsBenchmarkingBlock #:nodoc:
|
@@ -145,15 +158,16 @@ module RightAws
|
|
145
158
|
# Text, if found in an error message returned by AWS, indicates that this may be a transient
|
146
159
|
# error. Transient errors are automatically retried with exponential back-off.
|
147
160
|
AMAZON_PROBLEMS = [ 'internal service error',
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
161
|
+
'is currently unavailable',
|
162
|
+
'no response from',
|
163
|
+
'Please try again',
|
164
|
+
'InternalError',
|
165
|
+
'Internal Server Error',
|
166
|
+
'ServiceUnavailable', #from SQS docs
|
167
|
+
'Unavailable',
|
168
|
+
'This application is not currently available',
|
169
|
+
'InsufficientInstanceCapacity'
|
170
|
+
]
|
157
171
|
@@amazon_problems = AMAZON_PROBLEMS
|
158
172
|
# Returns a list of Amazon service responses which are known to be transient problems.
|
159
173
|
# We have to re-request if we get any of them, because the problem will probably disappear.
|
@@ -183,6 +197,8 @@ module RightAws
|
|
183
197
|
|
184
198
|
# Current aws_access_key_id
|
185
199
|
attr_reader :aws_access_key_id
|
200
|
+
# Current aws_secret_access_key
|
201
|
+
attr_reader :aws_secret_access_key
|
186
202
|
# Last HTTP request object
|
187
203
|
attr_reader :last_request
|
188
204
|
# Last HTTP response object
|
@@ -204,6 +220,9 @@ module RightAws
|
|
204
220
|
|
205
221
|
def init(service_info, aws_access_key_id, aws_secret_access_key, params={}) #:nodoc:
|
206
222
|
@params = params
|
223
|
+
# If one defines EC2_URL he may forget to use a single slash as an "empty service" path.
|
224
|
+
# Amazon does not like this therefore add this bad boy if he is missing...
|
225
|
+
service_info[:default_service] = '/' if service_info[:default_service].blank?
|
207
226
|
raise AwsError.new("AWS access keys are required to operate on #{service_info[:name]}") \
|
208
227
|
if aws_access_key_id.blank? || aws_secret_access_key.blank?
|
209
228
|
@aws_access_key_id = aws_access_key_id
|
@@ -213,6 +232,8 @@ module RightAws
|
|
213
232
|
@params[:server] = URI.parse(@params[:endpoint_url]).host
|
214
233
|
@params[:port] = URI.parse(@params[:endpoint_url]).port
|
215
234
|
@params[:service] = URI.parse(@params[:endpoint_url]).path
|
235
|
+
# make sure the 'service' path is not empty
|
236
|
+
@params[:service] = service_info[:default_service] if @params[:service].blank?
|
216
237
|
@params[:protocol] = URI.parse(@params[:endpoint_url]).scheme
|
217
238
|
@params[:region] = nil
|
218
239
|
else
|
@@ -222,11 +243,15 @@ module RightAws
|
|
222
243
|
@params[:service] ||= service_info[:default_service]
|
223
244
|
@params[:protocol] ||= service_info[:default_protocol]
|
224
245
|
end
|
225
|
-
@params[:multi_thread] ||= defined?(AWS_DAEMON)
|
246
|
+
# @params[:multi_thread] ||= defined?(AWS_DAEMON)
|
247
|
+
@params[:connections] ||= :shared # || :dedicated
|
248
|
+
@params[:max_connections] ||= 10
|
249
|
+
@params[:connection_lifetime] ||= 20*60
|
250
|
+
@params[:api_version] ||= service_info[:default_api_version]
|
226
251
|
@logger = @params[:logger]
|
227
252
|
@logger = RAILS_DEFAULT_LOGGER if !@logger && defined?(RAILS_DEFAULT_LOGGER)
|
228
253
|
@logger = Logger.new(STDOUT) if !@logger
|
229
|
-
@logger.info "New #{self.class.name} using #{@params[:
|
254
|
+
@logger.info "New #{self.class.name} using #{@params[:connections]} connections mode"
|
230
255
|
@error_handler = nil
|
231
256
|
@cache = {}
|
232
257
|
@signature_version = (params[:signature_version] || DEFAULT_SIGNATURE_VERSION).to_s
|
@@ -256,7 +281,8 @@ module RightAws
|
|
256
281
|
if caching?
|
257
282
|
function = function.to_sym
|
258
283
|
# get rid of requestId (this bad boy was added for API 2008-08-08+ and it is uniq for every response)
|
259
|
-
|
284
|
+
# feb 04, 2009 (load balancer uses 'RequestId' hence use 'i' modifier to hit it also)
|
285
|
+
response = response.sub(%r{<requestId>.+?</requestId>}i, '')
|
260
286
|
response_md5 = MD5.md5(response).to_s
|
261
287
|
# check for changes
|
262
288
|
unless @cache[function] && @cache[function][:response_md5] == response_md5
|
@@ -289,16 +315,85 @@ module RightAws
|
|
289
315
|
AwsError::on_aws_exception(self, options)
|
290
316
|
end
|
291
317
|
|
292
|
-
# Return +true+ if this instance works in multi_thread mode and +false+ otherwise.
|
293
|
-
def multi_thread
|
294
|
-
@params[:multi_thread]
|
318
|
+
# # Return +true+ if this instance works in multi_thread mode and +false+ otherwise.
|
319
|
+
# def multi_thread
|
320
|
+
# @params[:multi_thread]
|
321
|
+
# end
|
322
|
+
|
323
|
+
# ACF, AMS, EC2, LBS and SDB uses this guy
|
324
|
+
# SQS and S3 use their own methods
|
325
|
+
def generate_request_impl(verb, action, options={}) #:nodoc:
|
326
|
+
# Form a valid http verb: 'GET' or 'POST' (all the other are not supported now)
|
327
|
+
http_verb = verb.to_s.upcase
|
328
|
+
# remove empty keys from request options
|
329
|
+
options.delete_if { |key, value| value.nil? }
|
330
|
+
# prepare service data
|
331
|
+
service_hash = {"Action" => action,
|
332
|
+
"AWSAccessKeyId" => @aws_access_key_id,
|
333
|
+
"Version" => @params[:api_version] }
|
334
|
+
service_hash.merge!(options)
|
335
|
+
# Sign request options
|
336
|
+
service_params = signed_service_params(@aws_secret_access_key, service_hash, http_verb, @params[:server], @params[:service])
|
337
|
+
# Use POST if the length of the query string is too large
|
338
|
+
# see http://docs.amazonwebservices.com/AmazonSimpleDB/2007-11-07/DeveloperGuide/MakingRESTRequests.html
|
339
|
+
if http_verb != 'POST' && service_params.size > 2000
|
340
|
+
http_verb = 'POST'
|
341
|
+
if signature_version == '2'
|
342
|
+
service_params = signed_service_params(@aws_secret_access_key, service_hash, http_verb, @params[:server], @params[:service])
|
343
|
+
end
|
344
|
+
end
|
345
|
+
# create a request
|
346
|
+
case http_verb
|
347
|
+
when 'GET'
|
348
|
+
request = Net::HTTP::Get.new("#{@params[:service]}?#{service_params}")
|
349
|
+
when 'POST'
|
350
|
+
request = Net::HTTP::Post.new(@params[:service])
|
351
|
+
request.body = service_params
|
352
|
+
request['Content-Type'] = 'application/x-www-form-urlencoded; charset=utf-8'
|
353
|
+
else
|
354
|
+
raise "Unsupported HTTP verb #{verb.inspect}!"
|
355
|
+
end
|
356
|
+
# prepare output hash
|
357
|
+
{ :request => request,
|
358
|
+
:server => @params[:server],
|
359
|
+
:port => @params[:port],
|
360
|
+
:protocol => @params[:protocol] }
|
361
|
+
end
|
362
|
+
|
363
|
+
def get_connection(aws_service, request) #:nodoc
|
364
|
+
server_url = "#{request[:protocol]}://#{request[:server]}:#{request[:port]}}"
|
365
|
+
#
|
366
|
+
case @params[:connections].to_s
|
367
|
+
when 'dedicated'
|
368
|
+
@connections_storage ||= {}
|
369
|
+
else # 'dedicated'
|
370
|
+
@connections_storage = (Thread.current[aws_service] ||= {})
|
371
|
+
end
|
372
|
+
#
|
373
|
+
@connections_storage[server_url] ||= {}
|
374
|
+
@connections_storage[server_url][:last_used_at] = Time.now
|
375
|
+
@connections_storage[server_url][:connection] ||= Rightscale::HttpConnection.new(:exception => RightAws::AwsError, :logger => @logger)
|
376
|
+
# keep X most recent connections (but were used not far than Y minutes ago)
|
377
|
+
connections = 0
|
378
|
+
@connections_storage.to_a.sort{|i1, i2| i2[1][:last_used_at] <=> i1[1][:last_used_at]}.to_a.each do |i|
|
379
|
+
if i[0] != server_url && (@params[:max_connections] <= connections || i[1][:last_used_at] < Time.now - @params[:connection_lifetime])
|
380
|
+
# delete the connection from the list
|
381
|
+
@connections_storage.delete(i[0])
|
382
|
+
# then finish it
|
383
|
+
i[1][:connection].finish((@params[:max_connections] <= connections) ? "out-of-limit" : "out-of-date") rescue nil
|
384
|
+
else
|
385
|
+
connections += 1
|
386
|
+
end
|
387
|
+
end
|
388
|
+
@connections_storage[server_url][:connection]
|
295
389
|
end
|
296
390
|
|
297
|
-
|
298
|
-
|
391
|
+
# All services uses this guy.
|
392
|
+
def request_info_impl(aws_service, benchblock, request, parser, &block) #:nodoc:
|
393
|
+
@connection = get_connection(aws_service, request)
|
299
394
|
@last_request = request[:request]
|
300
395
|
@last_response = nil
|
301
|
-
response=nil
|
396
|
+
response = nil
|
302
397
|
blockexception = nil
|
303
398
|
|
304
399
|
if(block != nil)
|
@@ -382,7 +477,73 @@ module RightAws
|
|
382
477
|
|
383
478
|
# Returns Amazons request ID for the latest request
|
384
479
|
def last_request_id
|
385
|
-
@last_response && @last_response.body.to_s[%r{<requestId>(.+?)</requestId>}] && $1
|
480
|
+
@last_response && @last_response.body.to_s[%r{<requestId>(.+?)</requestId>}i] && $1
|
481
|
+
end
|
482
|
+
|
483
|
+
# Format array of items into Amazons handy hash ('?' is a place holder):
|
484
|
+
#
|
485
|
+
# amazonize_list('Item', ['a', 'b', 'c']) =>
|
486
|
+
# { 'Item.1' => 'a', 'Item.2' => 'b', 'Item.3' => 'c' }
|
487
|
+
#
|
488
|
+
# amazonize_list('Item.?.instance', ['a', 'c']) #=>
|
489
|
+
# { 'Item.1.instance' => 'a', 'Item.2.instance' => 'c' }
|
490
|
+
#
|
491
|
+
# amazonize_list(['Item.?.Name', 'Item.?.Value'], {'A' => 'a', 'B' => 'b'}) #=>
|
492
|
+
# { 'Item.1.Name' => 'A', 'Item.1.Value' => 'a',
|
493
|
+
# 'Item.2.Name' => 'B', 'Item.2.Value' => 'b' }
|
494
|
+
#
|
495
|
+
# amazonize_list(['Item.?.Name', 'Item.?.Value'], [['A','a'], ['B','b']]) #=>
|
496
|
+
# { 'Item.1.Name' => 'A', 'Item.1.Value' => 'a',
|
497
|
+
# 'Item.2.Name' => 'B', 'Item.2.Value' => 'b' }
|
498
|
+
#
|
499
|
+
# amazonize_list(['Filter.?.Key', 'Filter.?.Value.?'], {'A' => ['aa','ab'], 'B' => ['ba','bb']}) #=>
|
500
|
+
# amazonize_list(['Filter.?.Key', 'Filter.?.Value.?'], [['A',['aa','ab']], ['B',['ba','bb']]]) #=>
|
501
|
+
# {"Filter.1.Key"=>"A",
|
502
|
+
# "Filter.1.Value.1"=>"aa",
|
503
|
+
# "Filter.1.Value.2"=>"ab",
|
504
|
+
# "Filter.2.Key"=>"B",
|
505
|
+
# "Filter.2.Value.1"=>"ba",
|
506
|
+
# "Filter.2.Value.2"=>"bb"}
|
507
|
+
def amazonize_list(masks, list) #:nodoc:
|
508
|
+
groups = {}
|
509
|
+
Array(list).each_with_index do |list_item, i|
|
510
|
+
Array(masks).each_with_index do |mask, mask_idx|
|
511
|
+
key = mask[/\?/] ? mask.dup : mask.dup + '.?'
|
512
|
+
key.sub!('?', (i+1).to_s)
|
513
|
+
value = Array(list_item)[mask_idx]
|
514
|
+
if value.is_a?(Array)
|
515
|
+
groups.merge!(amazonize_list(key, value))
|
516
|
+
else
|
517
|
+
groups[key] = value
|
518
|
+
end
|
519
|
+
end
|
520
|
+
end
|
521
|
+
groups
|
522
|
+
end
|
523
|
+
|
524
|
+
BLOCK_DEVICE_KEY_MAPPING = { # :nodoc:
|
525
|
+
:device_name => 'DeviceName',
|
526
|
+
:virtual_name => 'VirtualName',
|
527
|
+
:no_device => 'NoDevice',
|
528
|
+
:ebs_snapshot_id => 'Ebs.SnapshotId',
|
529
|
+
:ebs_volume_size => 'Ebs.VolumeSize',
|
530
|
+
:ebs_delete_on_termination => 'Ebs.DeleteOnTermination' }
|
531
|
+
|
532
|
+
def amazonize_block_device_mappings(block_device_mappings, key = 'BlockDeviceMapping') # :nodoc:
|
533
|
+
result = {}
|
534
|
+
unless block_device_mappings.blank?
|
535
|
+
block_device_mappings = [block_device_mappings] unless block_device_mappings.is_a?(Array)
|
536
|
+
block_device_mappings.each_with_index do |b, idx|
|
537
|
+
BLOCK_DEVICE_KEY_MAPPING.each do |local_name, remote_name|
|
538
|
+
value = b[local_name]
|
539
|
+
case local_name
|
540
|
+
when :no_device then value = value ? '' : nil # allow to pass :no_device as boolean
|
541
|
+
end
|
542
|
+
result["#{key}.#{idx+1}.#{remote_name}"] = value unless value.nil?
|
543
|
+
end
|
544
|
+
end
|
545
|
+
end
|
546
|
+
result
|
386
547
|
end
|
387
548
|
|
388
549
|
end
|
@@ -518,7 +679,7 @@ module RightAws
|
|
518
679
|
last_errors_text = ''
|
519
680
|
response = @aws.last_response
|
520
681
|
# log error
|
521
|
-
request_text_data = "#{request[:server]}:#{request[:port]}#{request[:request].path}"
|
682
|
+
request_text_data = "#{request[:protocol]}://#{request[:server]}:#{request[:port]}#{request[:request].path}"
|
522
683
|
# is this a redirect?
|
523
684
|
# yes!
|
524
685
|
if response.is_a?(Net::HTTPRedirection)
|
@@ -528,33 +689,36 @@ module RightAws
|
|
528
689
|
@aws.logger.warn("##### #{@aws.class.name} returned an error: #{response.code} #{response.message}\n#{response.body} #####")
|
529
690
|
@aws.logger.warn("##### #{@aws.class.name} request: #{request_text_data} ####")
|
530
691
|
end
|
531
|
-
|
532
|
-
|
692
|
+
|
693
|
+
# Extract error/redirection message from the response body
|
694
|
+
# Amazon claims that a redirection must have a body but somethimes it is nil....
|
695
|
+
if response.body && response.body[/^(<\?xml|<ErrorResponse)/]
|
696
|
+
error_parser = RightErrorResponseParser.new
|
533
697
|
@aws.class.bench_xml.add! do
|
534
|
-
error_parser
|
535
|
-
error_parser.parse(response)
|
536
|
-
@aws.last_errors = error_parser.errors
|
537
|
-
@aws.last_request_id = error_parser.requestID
|
538
|
-
last_errors_text = @aws.last_errors.flatten.join("\n")
|
539
|
-
# on redirect :
|
540
|
-
if redirect_detected
|
541
|
-
location = response['location']
|
542
|
-
# ... log information and ...
|
543
|
-
@aws.logger.info("##### #{@aws.class.name} redirect requested: #{response.code} #{response.message} #####")
|
544
|
-
@aws.logger.info("##### New location: #{location} #####")
|
545
|
-
# ... fix the connection data
|
546
|
-
request[:server] = URI.parse(location).host
|
547
|
-
request[:protocol] = URI.parse(location).scheme
|
548
|
-
request[:port] = URI.parse(location).port
|
549
|
-
end
|
698
|
+
error_parser.parse(response.body)
|
550
699
|
end
|
551
|
-
|
700
|
+
@aws.last_errors = error_parser.errors
|
701
|
+
@aws.last_request_id = error_parser.requestID
|
702
|
+
last_errors_text = @aws.last_errors.flatten.join("\n")
|
703
|
+
else
|
552
704
|
@aws.last_errors = [[response.code, "#{response.message} (#{request_text_data})"]]
|
553
705
|
@aws.last_request_id = '-undefined-'
|
554
706
|
last_errors_text = response.message
|
555
707
|
end
|
556
|
-
|
557
|
-
|
708
|
+
|
709
|
+
# Ok, it is a redirect, find the new destination location
|
710
|
+
if redirect_detected
|
711
|
+
location = response['location']
|
712
|
+
# ... log information and ...
|
713
|
+
@aws.logger.info("##### #{@aws.class.name} redirect requested: #{response.code} #{response.message} #####")
|
714
|
+
@aws.logger.info(" Old location: #{request_text_data}")
|
715
|
+
@aws.logger.info(" New location: #{location}")
|
716
|
+
# ... fix the connection data
|
717
|
+
request[:server] = URI.parse(location).host
|
718
|
+
request[:protocol] = URI.parse(location).scheme
|
719
|
+
request[:port] = URI.parse(location).port
|
720
|
+
else
|
721
|
+
# Not a redirect but an error: try to find the error in our list
|
558
722
|
@errors_list.each do |error_to_find|
|
559
723
|
if last_errors_text[/#{error_to_find}/i]
|
560
724
|
error_found = true
|
@@ -564,6 +728,7 @@ module RightAws
|
|
564
728
|
end
|
565
729
|
end
|
566
730
|
end
|
731
|
+
|
567
732
|
# check the time has gone from the first error come
|
568
733
|
if redirect_detected || error_found
|
569
734
|
# Close the connection to the server and recreate a new one.
|
@@ -627,7 +792,7 @@ module RightAws
|
|
627
792
|
@right_aws_parser.tag_start(name, attr_hash)
|
628
793
|
end
|
629
794
|
def on_characters(chars)
|
630
|
-
@right_aws_parser.text(chars)
|
795
|
+
@right_aws_parser.text(chars)
|
631
796
|
end
|
632
797
|
def on_end_element(name)
|
633
798
|
@right_aws_parser.tag_end(name)
|
@@ -656,25 +821,30 @@ module RightAws
|
|
656
821
|
attr_accessor :result
|
657
822
|
attr_reader :xmlpath
|
658
823
|
attr_accessor :xml_lib
|
824
|
+
attr_reader :full_tag_name
|
825
|
+
attr_reader :tag
|
659
826
|
|
660
827
|
def initialize(params={})
|
661
828
|
@xmlpath = ''
|
829
|
+
@full_tag_name = ''
|
662
830
|
@result = false
|
663
831
|
@text = ''
|
832
|
+
@tag = ''
|
664
833
|
@xml_lib = params[:xml_lib] || @@xml_lib
|
665
834
|
@logger = params[:logger]
|
666
835
|
reset
|
667
836
|
end
|
668
837
|
def tag_start(name, attributes)
|
669
838
|
@text = ''
|
839
|
+
@tag = name
|
840
|
+
@full_tag_name += @full_tag_name.empty? ? name : "/#{name}"
|
670
841
|
tagstart(name, attributes)
|
671
|
-
@xmlpath
|
842
|
+
@xmlpath = @full_tag_name
|
672
843
|
end
|
673
844
|
def tag_end(name)
|
674
|
-
|
675
|
-
@xmlpath = $1
|
676
|
-
end
|
845
|
+
@xmlpath = @full_tag_name[/^(.*?)\/?#{name}$/] && $1
|
677
846
|
tagend(name)
|
847
|
+
@full_tag_name = @xmlpath
|
678
848
|
end
|
679
849
|
def text(text)
|
680
850
|
@text += text
|
@@ -711,14 +881,19 @@ module RightAws
|
|
711
881
|
# Parse the xml text
|
712
882
|
case @xml_lib
|
713
883
|
when 'libxml'
|
714
|
-
|
715
|
-
|
884
|
+
if XML::Parser::VERSION >= '0.9.9'
|
885
|
+
# avoid warning on every usage
|
886
|
+
xml = XML::SaxParser.string(xml_text)
|
887
|
+
else
|
888
|
+
xml = XML::SaxParser.new
|
889
|
+
xml.string = xml_text
|
890
|
+
end
|
716
891
|
# check libxml-ruby version
|
717
892
|
if XML::Parser::VERSION >= '0.5.1.0'
|
718
893
|
xml.callbacks = RightSaxParserCallback.new(self)
|
719
894
|
else
|
720
895
|
xml.on_start_element{|name, attr_hash| self.tag_start(name, attr_hash)}
|
721
|
-
xml.on_characters{ |text| self.text(text)}
|
896
|
+
xml.on_characters{ |text| self.text(text)}
|
722
897
|
xml.on_end_element{ |name| self.tag_end(name)}
|
723
898
|
end
|
724
899
|
xml.parse
|
@@ -793,5 +968,11 @@ module RightAws
|
|
793
968
|
end
|
794
969
|
end
|
795
970
|
|
971
|
+
class RightBoolResponseParser < RightAWSParser #:nodoc:
|
972
|
+
def tagend(name)
|
973
|
+
@result = (@text=='true') if name == 'return'
|
974
|
+
end
|
975
|
+
end
|
976
|
+
|
796
977
|
end
|
797
978
|
|
data/lib/awsbase/support.rb
CHANGED
data/lib/ec2/right_ec2.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#
|
2
|
-
# Copyright (c) 2007-
|
2
|
+
# Copyright (c) 2007-2009 RightScale Inc
|
3
3
|
#
|
4
4
|
# Permission is hereby granted, free of charge, to any person obtaining
|
5
5
|
# a copy of this software and associated documentation files (the
|
@@ -68,7 +68,7 @@ module RightAws
|
|
68
68
|
include RightAwsBaseInterface
|
69
69
|
|
70
70
|
# Amazon EC2 API version being used
|
71
|
-
API_VERSION = "
|
71
|
+
API_VERSION = "2009-11-30"
|
72
72
|
DEFAULT_HOST = "ec2.amazonaws.com"
|
73
73
|
DEFAULT_PATH = '/'
|
74
74
|
DEFAULT_PROTOCOL = 'https'
|
@@ -81,7 +81,7 @@ module RightAws
|
|
81
81
|
# Amazon EC2 Instance Types : http://www.amazon.com/b?ie=UTF8&node=370375011
|
82
82
|
# Default EC2 instance type (platform)
|
83
83
|
DEFAULT_INSTANCE_TYPE = 'm1.small'
|
84
|
-
INSTANCE_TYPES = ['m1.small','c1.medium','m1.large','m1.xlarge','c1.xlarge']
|
84
|
+
INSTANCE_TYPES = ['m1.small','c1.medium','m1.large','m1.xlarge','c1.xlarge', 'm2.xlarge', 'm2.2xlarge', 'm2.4xlarge']
|
85
85
|
|
86
86
|
@@bench = AwsBenchmarkingBlock.new
|
87
87
|
def self.bench_xml
|
@@ -107,753 +107,36 @@ module RightAws
|
|
107
107
|
# * <tt>:protocol</tt>: 'http' or 'https', default: DEFAULT_PROTOCOL
|
108
108
|
# * <tt>:multi_thread</tt>: true=HTTP connection per thread, false=per process
|
109
109
|
# * <tt>:logger</tt>: for log messages, default: RAILS_DEFAULT_LOGGER else STDOUT
|
110
|
-
# * <tt>:signature_version</tt>: The signature version : '0' or '
|
110
|
+
# * <tt>:signature_version</tt>: The signature version : '0','1' or '2'(default)
|
111
111
|
# * <tt>:cache</tt>: true/false: caching for: ec2_describe_images, describe_instances,
|
112
112
|
# describe_images_by_owner, describe_images_by_executable_by, describe_availability_zones,
|
113
113
|
# describe_security_groups, describe_key_pairs, describe_addresses,
|
114
114
|
# describe_volumes, describe_snapshots methods, default: false.
|
115
115
|
#
|
116
116
|
def initialize(aws_access_key_id=nil, aws_secret_access_key=nil, params={})
|
117
|
-
init({ :name
|
118
|
-
:default_host
|
119
|
-
:default_port
|
120
|
-
:default_service
|
121
|
-
:default_protocol
|
117
|
+
init({ :name => 'EC2',
|
118
|
+
:default_host => ENV['EC2_URL'] ? URI.parse(ENV['EC2_URL']).host : DEFAULT_HOST,
|
119
|
+
:default_port => ENV['EC2_URL'] ? URI.parse(ENV['EC2_URL']).port : DEFAULT_PORT,
|
120
|
+
:default_service => ENV['EC2_URL'] ? URI.parse(ENV['EC2_URL']).path : DEFAULT_PATH,
|
121
|
+
:default_protocol => ENV['EC2_URL'] ? URI.parse(ENV['EC2_URL']).scheme : DEFAULT_PROTOCOL,
|
122
|
+
:default_api_version => @@api },
|
122
123
|
aws_access_key_id || ENV['AWS_ACCESS_KEY_ID'] ,
|
123
124
|
aws_secret_access_key|| ENV['AWS_SECRET_ACCESS_KEY'],
|
124
125
|
params)
|
125
|
-
#
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
# list)
|
130
|
-
amazon_problems = ['InternalError']
|
126
|
+
# Eucalyptus supports some yummy features but Amazon does not
|
127
|
+
if @params[:eucalyptus]
|
128
|
+
@params[:port_based_group_ingress] = true unless @params.has_key?(:port_based_group_ingress)
|
129
|
+
end
|
131
130
|
end
|
132
131
|
|
133
|
-
|
134
132
|
def generate_request(action, params={}) #:nodoc:
|
135
|
-
|
136
|
-
"AWSAccessKeyId" => @aws_access_key_id,
|
137
|
-
"Version" => @@api }
|
138
|
-
service_hash.update(params)
|
139
|
-
service_params = signed_service_params(@aws_secret_access_key, service_hash, :get, @params[:server], @params[:service])
|
140
|
-
|
141
|
-
# use POST method if the length of the query string is too large
|
142
|
-
if service_params.size > 2000
|
143
|
-
if signature_version == '2'
|
144
|
-
# resign the request because HTTP verb is included into signature
|
145
|
-
service_params = signed_service_params(@aws_secret_access_key, service_hash, :post, @params[:server], @params[:service])
|
146
|
-
end
|
147
|
-
request = Net::HTTP::Post.new(service)
|
148
|
-
request.body = service_params
|
149
|
-
request['Content-Type'] = 'application/x-www-form-urlencoded'
|
150
|
-
else
|
151
|
-
request = Net::HTTP::Get.new("#{@params[:service]}?#{service_params}")
|
152
|
-
end
|
153
|
-
# prepare output hash
|
154
|
-
{ :request => request,
|
155
|
-
:server => @params[:server],
|
156
|
-
:port => @params[:port],
|
157
|
-
:protocol => @params[:protocol] }
|
133
|
+
generate_request_impl(:get, action, params )
|
158
134
|
end
|
159
135
|
|
160
136
|
# Sends request to Amazon and parses the response
|
161
137
|
# Raises AwsError if any banana happened
|
162
138
|
def request_info(request, parser) #:nodoc:
|
163
|
-
|
164
|
-
thread[:ec2_connection] ||= Rightscale::HttpConnection.new(:exception => AwsError, :logger => @logger)
|
165
|
-
request_info_impl(thread[:ec2_connection], @@bench, request, parser)
|
166
|
-
end
|
167
|
-
|
168
|
-
def hash_params(prefix, list) #:nodoc:
|
169
|
-
groups = {}
|
170
|
-
list.each_index{|i| groups.update("#{prefix}.#{i+1}"=>list[i])} if list
|
171
|
-
return groups
|
172
|
-
end
|
173
|
-
|
174
|
-
#-----------------------------------------------------------------
|
175
|
-
# Images
|
176
|
-
#-----------------------------------------------------------------
|
177
|
-
|
178
|
-
# params:
|
179
|
-
# { 'ImageId' => ['id1', ..., 'idN'],
|
180
|
-
# 'Owner' => ['self', ..., 'userN'],
|
181
|
-
# 'ExecutableBy' => ['self', 'all', ..., 'userN']
|
182
|
-
# }
|
183
|
-
def ec2_describe_images(params={}, image_type=nil, cache_for=nil) #:nodoc:
|
184
|
-
request_hash = {}
|
185
|
-
params.each do |list_by, list|
|
186
|
-
request_hash.merge! hash_params(list_by, list.to_a)
|
187
|
-
end
|
188
|
-
request_hash['ImageType'] = image_type if image_type
|
189
|
-
link = generate_request("DescribeImages", request_hash)
|
190
|
-
request_cache_or_info cache_for, link, QEc2DescribeImagesParser, @@bench, cache_for
|
191
|
-
rescue Exception
|
192
|
-
on_exception
|
193
|
-
end
|
194
|
-
|
195
|
-
# Retrieve a list of images. Returns array of hashes describing the images or an exception:
|
196
|
-
# +image_type+ = 'machine' || 'kernel' || 'ramdisk'
|
197
|
-
#
|
198
|
-
# ec2.describe_images #=>
|
199
|
-
# [{:aws_owner => "522821470517",
|
200
|
-
# :aws_id => "ami-e4b6538d",
|
201
|
-
# :aws_state => "available",
|
202
|
-
# :aws_location => "marcins_cool_public_images/ubuntu-6.10.manifest.xml",
|
203
|
-
# :aws_is_public => true,
|
204
|
-
# :aws_architecture => "i386",
|
205
|
-
# :aws_image_type => "machine"},
|
206
|
-
# {...},
|
207
|
-
# {...} ]
|
208
|
-
#
|
209
|
-
# If +list+ param is set, then retrieve information about the listed images only:
|
210
|
-
#
|
211
|
-
# ec2.describe_images(['ami-e4b6538d']) #=>
|
212
|
-
# [{:aws_owner => "522821470517",
|
213
|
-
# :aws_id => "ami-e4b6538d",
|
214
|
-
# :aws_state => "available",
|
215
|
-
# :aws_location => "marcins_cool_public_images/ubuntu-6.10.manifest.xml",
|
216
|
-
# :aws_is_public => true,
|
217
|
-
# :aws_architecture => "i386",
|
218
|
-
# :aws_image_type => "machine"}]
|
219
|
-
#
|
220
|
-
def describe_images(list=[], image_type=nil)
|
221
|
-
list = list.to_a
|
222
|
-
cache_for = list.empty? && !image_type ? :describe_images : nil
|
223
|
-
ec2_describe_images({ 'ImageId' => list }, image_type, cache_for)
|
224
|
-
end
|
225
|
-
|
226
|
-
#
|
227
|
-
# Example:
|
228
|
-
#
|
229
|
-
# ec2.describe_images_by_owner('522821470517')
|
230
|
-
# ec2.describe_images_by_owner('self')
|
231
|
-
#
|
232
|
-
def describe_images_by_owner(list=['self'], image_type=nil)
|
233
|
-
list = list.to_a
|
234
|
-
cache_for = list==['self'] && !image_type ? :describe_images_by_owner : nil
|
235
|
-
ec2_describe_images({ 'Owner' => list }, image_type, cache_for)
|
236
|
-
end
|
237
|
-
|
238
|
-
#
|
239
|
-
# Example:
|
240
|
-
#
|
241
|
-
# ec2.describe_images_by_executable_by('522821470517')
|
242
|
-
# ec2.describe_images_by_executable_by('self')
|
243
|
-
# ec2.describe_images_by_executable_by('all')
|
244
|
-
#
|
245
|
-
def describe_images_by_executable_by(list=['self'], image_type=nil)
|
246
|
-
list = list.to_a
|
247
|
-
cache_for = list==['self'] && !image_type ? :describe_images_by_executable_by : nil
|
248
|
-
ec2_describe_images({ 'ExecutableBy' => list }, image_type, cache_for)
|
249
|
-
end
|
250
|
-
|
251
|
-
|
252
|
-
# Register new image at Amazon.
|
253
|
-
# Returns new image id or an exception.
|
254
|
-
#
|
255
|
-
# ec2.register_image('bucket/key/manifest') #=> 'ami-e444444d'
|
256
|
-
#
|
257
|
-
def register_image(image_location)
|
258
|
-
link = generate_request("RegisterImage",
|
259
|
-
'ImageLocation' => image_location.to_s)
|
260
|
-
request_info(link, QEc2RegisterImageParser.new(:logger => @logger))
|
261
|
-
rescue Exception
|
262
|
-
on_exception
|
263
|
-
end
|
264
|
-
|
265
|
-
# Deregister image at Amazon. Returns +true+ or an exception.
|
266
|
-
#
|
267
|
-
# ec2.deregister_image('ami-e444444d') #=> true
|
268
|
-
#
|
269
|
-
def deregister_image(image_id)
|
270
|
-
link = generate_request("DeregisterImage",
|
271
|
-
'ImageId' => image_id.to_s)
|
272
|
-
request_info(link, RightBoolResponseParser.new(:logger => @logger))
|
273
|
-
rescue Exception
|
274
|
-
on_exception
|
275
|
-
end
|
276
|
-
|
277
|
-
|
278
|
-
# Describe image attributes. Currently 'launchPermission', 'productCodes', 'kernel', 'ramdisk' and 'blockDeviceMapping' are supported.
|
279
|
-
#
|
280
|
-
# ec2.describe_image_attribute('ami-e444444d') #=> {:groups=>["all"], :users=>["000000000777"]}
|
281
|
-
#
|
282
|
-
def describe_image_attribute(image_id, attribute='launchPermission')
|
283
|
-
link = generate_request("DescribeImageAttribute",
|
284
|
-
'ImageId' => image_id,
|
285
|
-
'Attribute' => attribute)
|
286
|
-
request_info(link, QEc2DescribeImageAttributeParser.new(:logger => @logger))
|
287
|
-
rescue Exception
|
288
|
-
on_exception
|
289
|
-
end
|
290
|
-
|
291
|
-
# Reset image attribute. Currently, only 'launchPermission' is supported. Returns +true+ or an exception.
|
292
|
-
#
|
293
|
-
# ec2.reset_image_attribute('ami-e444444d') #=> true
|
294
|
-
#
|
295
|
-
def reset_image_attribute(image_id, attribute='launchPermission')
|
296
|
-
link = generate_request("ResetImageAttribute",
|
297
|
-
'ImageId' => image_id,
|
298
|
-
'Attribute' => attribute)
|
299
|
-
request_info(link, RightBoolResponseParser.new(:logger => @logger))
|
300
|
-
rescue Exception
|
301
|
-
on_exception
|
302
|
-
end
|
303
|
-
|
304
|
-
# Modify an image's attributes. It is recommended that you use
|
305
|
-
# modify_image_launch_perm_add_users, modify_image_launch_perm_remove_users, etc.
|
306
|
-
# instead of modify_image_attribute because the signature of
|
307
|
-
# modify_image_attribute may change with EC2 service changes.
|
308
|
-
#
|
309
|
-
# attribute : currently, only 'launchPermission' is supported.
|
310
|
-
# operation_type : currently, only 'add' & 'remove' are supported.
|
311
|
-
# vars:
|
312
|
-
# :user_group : currently, only 'all' is supported.
|
313
|
-
# :user_id
|
314
|
-
# :product_code
|
315
|
-
def modify_image_attribute(image_id, attribute, operation_type = nil, vars = {})
|
316
|
-
params = {'ImageId' => image_id,
|
317
|
-
'Attribute' => attribute}
|
318
|
-
params['OperationType'] = operation_type if operation_type
|
319
|
-
params.update(hash_params('UserId', vars[:user_id].to_a)) if vars[:user_id]
|
320
|
-
params.update(hash_params('UserGroup', vars[:user_group].to_a)) if vars[:user_group]
|
321
|
-
params.update(hash_params('ProductCode', vars[:product_code])) if vars[:product_code]
|
322
|
-
link = generate_request("ModifyImageAttribute", params)
|
323
|
-
request_info(link, RightBoolResponseParser.new(:logger => @logger))
|
324
|
-
rescue Exception
|
325
|
-
on_exception
|
326
|
-
end
|
327
|
-
|
328
|
-
# Grant image launch permissions to users.
|
329
|
-
# Parameter +userId+ is a list of user AWS account ids.
|
330
|
-
# Returns +true+ or an exception.
|
331
|
-
#
|
332
|
-
# ec2.modify_image_launch_perm_add_users('ami-e444444d',['000000000777','000000000778']) #=> true
|
333
|
-
def modify_image_launch_perm_add_users(image_id, user_id=[])
|
334
|
-
modify_image_attribute(image_id, 'launchPermission', 'add', :user_id => user_id.to_a)
|
335
|
-
end
|
336
|
-
|
337
|
-
# Revokes image launch permissions for users. +userId+ is a list of users AWS accounts ids. Returns +true+ or an exception.
|
338
|
-
#
|
339
|
-
# ec2.modify_image_launch_perm_remove_users('ami-e444444d',['000000000777','000000000778']) #=> true
|
340
|
-
#
|
341
|
-
def modify_image_launch_perm_remove_users(image_id, user_id=[])
|
342
|
-
modify_image_attribute(image_id, 'launchPermission', 'remove', :user_id => user_id.to_a)
|
343
|
-
end
|
344
|
-
|
345
|
-
# Add image launch permissions for users groups (currently only 'all' is supported, which gives public launch permissions).
|
346
|
-
# Returns +true+ or an exception.
|
347
|
-
#
|
348
|
-
# ec2.modify_image_launch_perm_add_groups('ami-e444444d') #=> true
|
349
|
-
#
|
350
|
-
def modify_image_launch_perm_add_groups(image_id, user_group=['all'])
|
351
|
-
modify_image_attribute(image_id, 'launchPermission', 'add', :user_group => user_group.to_a)
|
352
|
-
end
|
353
|
-
|
354
|
-
# Remove image launch permissions for users groups (currently only 'all' is supported, which gives public launch permissions).
|
355
|
-
#
|
356
|
-
# ec2.modify_image_launch_perm_remove_groups('ami-e444444d') #=> true
|
357
|
-
#
|
358
|
-
def modify_image_launch_perm_remove_groups(image_id, user_group=['all'])
|
359
|
-
modify_image_attribute(image_id, 'launchPermission', 'remove', :user_group => user_group.to_a)
|
360
|
-
end
|
361
|
-
|
362
|
-
# Add product code to image
|
363
|
-
#
|
364
|
-
# ec2.modify_image_product_code('ami-e444444d','0ABCDEF') #=> true
|
365
|
-
#
|
366
|
-
def modify_image_product_code(image_id, product_code=[])
|
367
|
-
modify_image_attribute(image_id, 'productCodes', nil, :product_code => product_code.to_a)
|
368
|
-
end
|
369
|
-
|
370
|
-
#-----------------------------------------------------------------
|
371
|
-
# Instances
|
372
|
-
#-----------------------------------------------------------------
|
373
|
-
|
374
|
-
def get_desc_instances(instances) # :nodoc:
|
375
|
-
result = []
|
376
|
-
instances.each do |reservation|
|
377
|
-
reservation[:instances_set].each do |instance|
|
378
|
-
# Parse and remove timestamp from the reason string. The timestamp is of
|
379
|
-
# the request, not when EC2 took action, thus confusing & useless...
|
380
|
-
instance[:aws_reason] = instance[:aws_reason].sub(/\(\d[^)]*GMT\) */, '')
|
381
|
-
instance[:aws_owner] = reservation[:aws_owner]
|
382
|
-
instance[:aws_reservation_id] = reservation[:aws_reservation_id]
|
383
|
-
instance[:aws_groups] = reservation[:aws_groups]
|
384
|
-
result << instance
|
385
|
-
end
|
386
|
-
end
|
387
|
-
result
|
388
|
-
rescue Exception
|
389
|
-
on_exception
|
390
|
-
end
|
391
|
-
|
392
|
-
# Retrieve information about EC2 instances. If +list+ is omitted then returns the
|
393
|
-
# list of all instances.
|
394
|
-
#
|
395
|
-
# ec2.describe_instances #=>
|
396
|
-
# [{:aws_image_id => "ami-e444444d",
|
397
|
-
# :aws_reason => "",
|
398
|
-
# :aws_state_code => "16",
|
399
|
-
# :aws_owner => "000000000888",
|
400
|
-
# :aws_instance_id => "i-123f1234",
|
401
|
-
# :aws_reservation_id => "r-aabbccdd",
|
402
|
-
# :aws_state => "running",
|
403
|
-
# :dns_name => "domU-12-34-67-89-01-C9.usma2.compute.amazonaws.com",
|
404
|
-
# :ssh_key_name => "staging",
|
405
|
-
# :aws_groups => ["default"],
|
406
|
-
# :private_dns_name => "domU-12-34-67-89-01-C9.usma2.compute.amazonaws.com",
|
407
|
-
# :aws_instance_type => "m1.small",
|
408
|
-
# :aws_launch_time => "2008-1-1T00:00:00.000Z"},
|
409
|
-
# :aws_availability_zone => "us-east-1b",
|
410
|
-
# :aws_kernel_id => "aki-ba3adfd3",
|
411
|
-
# :aws_ramdisk_id => "ari-badbad00",
|
412
|
-
# ..., {...}]
|
413
|
-
#
|
414
|
-
def describe_instances(list=[])
|
415
|
-
link = generate_request("DescribeInstances", hash_params('InstanceId',list.to_a))
|
416
|
-
request_cache_or_info(:describe_instances, link, QEc2DescribeInstancesParser, @@bench, list.blank?) do |parser|
|
417
|
-
get_desc_instances(parser.result)
|
418
|
-
end
|
419
|
-
rescue Exception
|
420
|
-
on_exception
|
421
|
-
end
|
422
|
-
|
423
|
-
# Return the product code attached to instance or +nil+ otherwise.
|
424
|
-
#
|
425
|
-
# ec2.confirm_product_instance('ami-e444444d','12345678') #=> nil
|
426
|
-
# ec2.confirm_product_instance('ami-e444444d','00001111') #=> "000000000888"
|
427
|
-
#
|
428
|
-
def confirm_product_instance(instance, product_code)
|
429
|
-
link = generate_request("ConfirmProductInstance", { 'ProductCode' => product_code,
|
430
|
-
'InstanceId' => instance })
|
431
|
-
request_info(link, QEc2ConfirmProductInstanceParser.new(:logger => @logger))
|
432
|
-
end
|
433
|
-
|
434
|
-
# Launch new EC2 instances. Returns a list of launched instances or an exception.
|
435
|
-
#
|
436
|
-
# ec2.run_instances('ami-e444444d',1,1,['my_awesome_group'],'my_awesome_key', 'Woohoo!!!', 'public') #=>
|
437
|
-
# [{:aws_image_id => "ami-e444444d",
|
438
|
-
# :aws_reason => "",
|
439
|
-
# :aws_state_code => "0",
|
440
|
-
# :aws_owner => "000000000888",
|
441
|
-
# :aws_instance_id => "i-123f1234",
|
442
|
-
# :aws_reservation_id => "r-aabbccdd",
|
443
|
-
# :aws_state => "pending",
|
444
|
-
# :dns_name => "",
|
445
|
-
# :ssh_key_name => "my_awesome_key",
|
446
|
-
# :aws_groups => ["my_awesome_group"],
|
447
|
-
# :private_dns_name => "",
|
448
|
-
# :aws_instance_type => "m1.small",
|
449
|
-
# :aws_launch_time => "2008-1-1T00:00:00.000Z"
|
450
|
-
# :aws_ramdisk_id => "ari-8605e0ef"
|
451
|
-
# :aws_kernel_id => "aki-9905e0f0",
|
452
|
-
# :ami_launch_index => "0",
|
453
|
-
# :aws_availability_zone => "us-east-1b"
|
454
|
-
# }]
|
455
|
-
#
|
456
|
-
def run_instances(image_id, min_count, max_count, group_ids, key_name, user_data='',
|
457
|
-
addressing_type = nil, instance_type = nil,
|
458
|
-
kernel_id = nil, ramdisk_id = nil, availability_zone = nil,
|
459
|
-
block_device_mappings = nil)
|
460
|
-
launch_instances(image_id, { :min_count => min_count,
|
461
|
-
:max_count => max_count,
|
462
|
-
:user_data => user_data,
|
463
|
-
:group_ids => group_ids,
|
464
|
-
:key_name => key_name,
|
465
|
-
:instance_type => instance_type,
|
466
|
-
:addressing_type => addressing_type,
|
467
|
-
:kernel_id => kernel_id,
|
468
|
-
:ramdisk_id => ramdisk_id,
|
469
|
-
:availability_zone => availability_zone,
|
470
|
-
:block_device_mappings => block_device_mappings
|
471
|
-
})
|
472
|
-
end
|
473
|
-
|
474
|
-
|
475
|
-
# Launch new EC2 instances. Returns a list of launched instances or an exception.
|
476
|
-
#
|
477
|
-
# +lparams+ keys (default values in parenthesis):
|
478
|
-
# :min_count fixnum, (1)
|
479
|
-
# :max_count fixnum, (1)
|
480
|
-
# :group_ids array or string ([] == 'default')
|
481
|
-
# :instance_type string (DEFAULT_INSTACE_TYPE)
|
482
|
-
# :addressing_type string (DEFAULT_ADDRESSING_TYPE
|
483
|
-
# :key_name string
|
484
|
-
# :kernel_id string
|
485
|
-
# :ramdisk_id string
|
486
|
-
# :availability_zone string
|
487
|
-
# :block_device_mappings string
|
488
|
-
# :user_data string
|
489
|
-
#
|
490
|
-
# ec2.launch_instances('ami-e444444d', :group_ids => 'my_awesome_group',
|
491
|
-
# :user_data => "Woohoo!!!",
|
492
|
-
# :addressing_type => "public",
|
493
|
-
# :key_name => "my_awesome_key",
|
494
|
-
# :availability_zone => "us-east-1c") #=>
|
495
|
-
# [{:aws_image_id => "ami-e444444d",
|
496
|
-
# :aws_reason => "",
|
497
|
-
# :aws_state_code => "0",
|
498
|
-
# :aws_owner => "000000000888",
|
499
|
-
# :aws_instance_id => "i-123f1234",
|
500
|
-
# :aws_reservation_id => "r-aabbccdd",
|
501
|
-
# :aws_state => "pending",
|
502
|
-
# :dns_name => "",
|
503
|
-
# :ssh_key_name => "my_awesome_key",
|
504
|
-
# :aws_groups => ["my_awesome_group"],
|
505
|
-
# :private_dns_name => "",
|
506
|
-
# :aws_instance_type => "m1.small",
|
507
|
-
# :aws_launch_time => "2008-1-1T00:00:00.000Z",
|
508
|
-
# :aws_ramdisk_id => "ari-8605e0ef"
|
509
|
-
# :aws_kernel_id => "aki-9905e0f0",
|
510
|
-
# :ami_launch_index => "0",
|
511
|
-
# :aws_availability_zone => "us-east-1c"
|
512
|
-
# }]
|
513
|
-
#
|
514
|
-
def launch_instances(image_id, lparams={})
|
515
|
-
@logger.info("Launching instance of image #{image_id} for #{@aws_access_key_id}, " +
|
516
|
-
"key: #{lparams[:key_name]}, groups: #{(lparams[:group_ids]).to_a.join(',')}")
|
517
|
-
# careful: keyName and securityGroups may be nil
|
518
|
-
params = hash_params('SecurityGroup', lparams[:group_ids].to_a)
|
519
|
-
params.update( {'ImageId' => image_id,
|
520
|
-
'MinCount' => (lparams[:min_count] || 1).to_s,
|
521
|
-
'MaxCount' => (lparams[:max_count] || 1).to_s,
|
522
|
-
'AddressingType' => lparams[:addressing_type] || DEFAULT_ADDRESSING_TYPE,
|
523
|
-
'InstanceType' => lparams[:instance_type] || DEFAULT_INSTANCE_TYPE })
|
524
|
-
# optional params
|
525
|
-
params['KeyName'] = lparams[:key_name] unless lparams[:key_name].blank?
|
526
|
-
params['KernelId'] = lparams[:kernel_id] unless lparams[:kernel_id].blank?
|
527
|
-
params['RamdiskId'] = lparams[:ramdisk_id] unless lparams[:ramdisk_id].blank?
|
528
|
-
params['Placement.AvailabilityZone'] = lparams[:availability_zone] unless lparams[:availability_zone].blank?
|
529
|
-
params['BlockDeviceMappings'] = lparams[:block_device_mappings] unless lparams[:block_device_mappings].blank?
|
530
|
-
unless lparams[:user_data].blank?
|
531
|
-
lparams[:user_data].strip!
|
532
|
-
# Do not use CGI::escape(encode64(...)) as it is done in Amazons EC2 library.
|
533
|
-
# Amazon 169.254.169.254 does not like escaped symbols!
|
534
|
-
# And it doesn't like "\n" inside of encoded string! Grrr....
|
535
|
-
# Otherwise, some of UserData symbols will be lost...
|
536
|
-
params['UserData'] = Base64.encode64(lparams[:user_data]).delete("\n").strip unless lparams[:user_data].blank?
|
537
|
-
end
|
538
|
-
link = generate_request("RunInstances", params)
|
539
|
-
#debugger
|
540
|
-
instances = request_info(link, QEc2DescribeInstancesParser.new(:logger => @logger))
|
541
|
-
get_desc_instances(instances)
|
542
|
-
rescue Exception
|
543
|
-
on_exception
|
544
|
-
end
|
545
|
-
|
546
|
-
# Terminates EC2 instances. Returns a list of termination params or an exception.
|
547
|
-
#
|
548
|
-
# ec2.terminate_instances(['i-f222222d','i-f222222e']) #=>
|
549
|
-
# [{:aws_shutdown_state => "shutting-down",
|
550
|
-
# :aws_instance_id => "i-f222222d",
|
551
|
-
# :aws_shutdown_state_code => 32,
|
552
|
-
# :aws_prev_state => "running",
|
553
|
-
# :aws_prev_state_code => 16},
|
554
|
-
# {:aws_shutdown_state => "shutting-down",
|
555
|
-
# :aws_instance_id => "i-f222222e",
|
556
|
-
# :aws_shutdown_state_code => 32,
|
557
|
-
# :aws_prev_state => "running",
|
558
|
-
# :aws_prev_state_code => 16}]
|
559
|
-
#
|
560
|
-
def terminate_instances(list=[])
|
561
|
-
link = generate_request("TerminateInstances", hash_params('InstanceId',list.to_a))
|
562
|
-
request_info(link, QEc2TerminateInstancesParser.new(:logger => @logger))
|
563
|
-
rescue Exception
|
564
|
-
on_exception
|
565
|
-
end
|
566
|
-
|
567
|
-
# Retreive EC2 instance OS logs. Returns a hash of data or an exception.
|
568
|
-
#
|
569
|
-
# ec2.get_console_output('i-f222222d') =>
|
570
|
-
# {:aws_instance_id => 'i-f222222d',
|
571
|
-
# :aws_timestamp => "2007-05-23T14:36:07.000-07:00",
|
572
|
-
# :timestamp => Wed May 23 21:36:07 UTC 2007, # Time instance
|
573
|
-
# :aws_output => "Linux version 2.6.16-xenU (builder@patchbat.amazonsa) (gcc version 4.0.1 20050727 ..."
|
574
|
-
def get_console_output(instance_id)
|
575
|
-
link = generate_request("GetConsoleOutput", { 'InstanceId.1' => instance_id })
|
576
|
-
request_info(link, QEc2GetConsoleOutputParser.new(:logger => @logger))
|
577
|
-
rescue Exception
|
578
|
-
on_exception
|
579
|
-
end
|
580
|
-
|
581
|
-
# Reboot an EC2 instance. Returns +true+ or an exception.
|
582
|
-
#
|
583
|
-
# ec2.reboot_instances(['i-f222222d','i-f222222e']) #=> true
|
584
|
-
#
|
585
|
-
def reboot_instances(list)
|
586
|
-
link = generate_request("RebootInstances", hash_params('InstanceId', list.to_a))
|
587
|
-
request_info(link, RightBoolResponseParser.new(:logger => @logger))
|
588
|
-
rescue Exception
|
589
|
-
on_exception
|
590
|
-
end
|
591
|
-
|
592
|
-
#-----------------------------------------------------------------
|
593
|
-
# Instances: Windows addons
|
594
|
-
#-----------------------------------------------------------------
|
595
|
-
|
596
|
-
# Get initial Windows Server setup password from an instance console output.
|
597
|
-
#
|
598
|
-
# my_awesome_key = ec2.create_key_pair('my_awesome_key') #=>
|
599
|
-
# {:aws_key_name => "my_awesome_key",
|
600
|
-
# :aws_fingerprint => "01:02:03:f4:25:e6:97:e8:9b:02:1a:26:32:4e:58:6b:7a:8c:9f:03",
|
601
|
-
# :aws_material => "-----BEGIN RSA PRIVATE KEY-----\nMIIEpQIBAAK...Q8MDrCbuQ=\n-----END RSA PRIVATE KEY-----"}
|
602
|
-
#
|
603
|
-
# my_awesome_instance = ec2.run_instances('ami-a000000a',1,1,['my_awesome_group'],'my_awesome_key', 'WindowsInstance!!!') #=>
|
604
|
-
# [{:aws_image_id => "ami-a000000a",
|
605
|
-
# :aws_instance_id => "i-12345678",
|
606
|
-
# ...
|
607
|
-
# :aws_availability_zone => "us-east-1b"
|
608
|
-
# }]
|
609
|
-
#
|
610
|
-
# # wait until instance enters 'operational' state and get it's initial password
|
611
|
-
#
|
612
|
-
# puts ec2.get_initial_password(my_awesome_instance[:aws_instance_id], my_awesome_key[:aws_material]) #=> "MhjWcgZuY6"
|
613
|
-
#
|
614
|
-
def get_initial_password(instance_id, private_key)
|
615
|
-
console_output = get_console_output(instance_id)
|
616
|
-
crypted_password = console_output[:aws_output][%r{<Password>(.+)</Password>}m] && $1
|
617
|
-
unless crypted_password
|
618
|
-
raise AwsError.new("Initial password was not found in console output for #{instance_id}")
|
619
|
-
else
|
620
|
-
OpenSSL::PKey::RSA.new(private_key).private_decrypt(Base64.decode64(crypted_password))
|
621
|
-
end
|
622
|
-
rescue Exception
|
623
|
-
on_exception
|
624
|
-
end
|
625
|
-
|
626
|
-
# Bundle a Windows image.
|
627
|
-
# Internally, it queues the bundling task and shuts down the instance.
|
628
|
-
# It then takes a snapshot of the Windows volume bundles it, and uploads it to
|
629
|
-
# S3. After bundling completes, Rightaws::Ec2#register_image may be used to
|
630
|
-
# register the new Windows AMI for subsequent launches.
|
631
|
-
#
|
632
|
-
# ec2.bundle_instance('i-e3e24e8a', 'my-awesome-bucket', 'my-win-image-1') #=>
|
633
|
-
# [{:aws_update_time => "2008-10-16T13:58:25.000Z",
|
634
|
-
# :s3_bucket => "kd-win-1",
|
635
|
-
# :s3_prefix => "win2pr",
|
636
|
-
# :aws_state => "pending",
|
637
|
-
# :aws_id => "bun-26a7424f",
|
638
|
-
# :aws_instance_id => "i-878a25ee",
|
639
|
-
# :aws_start_time => "2008-10-16T13:58:02.000Z"}]
|
640
|
-
#
|
641
|
-
def bundle_instance(instance_id, s3_bucket, s3_prefix,
|
642
|
-
s3_owner_aws_access_key_id=nil, s3_owner_aws_secret_access_key=nil,
|
643
|
-
s3_expires = S3Interface::DEFAULT_EXPIRES_AFTER,
|
644
|
-
s3_upload_policy='ec2-bundle-read')
|
645
|
-
# S3 access and signatures
|
646
|
-
s3_owner_aws_access_key_id ||= @aws_access_key_id
|
647
|
-
s3_owner_aws_secret_access_key ||= @aws_secret_access_key
|
648
|
-
s3_expires = Time.now.utc + s3_expires if s3_expires.is_a?(Fixnum) && (s3_expires < S3Interface::ONE_YEAR_IN_SECONDS)
|
649
|
-
# policy
|
650
|
-
policy = { 'expiration' => s3_expires.strftime('%Y-%m-%dT%H:%M:%SZ'),
|
651
|
-
'conditions' => [ { 'bucket' => s3_bucket },
|
652
|
-
{ 'acl' => s3_upload_policy },
|
653
|
-
[ 'starts-with', '$key', s3_prefix ] ] }.to_json
|
654
|
-
policy64 = Base64.encode64(policy).gsub("\n","")
|
655
|
-
signed_policy64 = AwsUtils.sign(s3_owner_aws_secret_access_key, policy64)
|
656
|
-
# fill request params
|
657
|
-
params = { 'InstanceId' => instance_id,
|
658
|
-
'Storage.S3.AWSAccessKeyId' => s3_owner_aws_access_key_id,
|
659
|
-
'Storage.S3.UploadPolicy' => policy64,
|
660
|
-
'Storage.S3.UploadPolicySignature' => signed_policy64,
|
661
|
-
'Storage.S3.Bucket' => s3_bucket,
|
662
|
-
'Storage.S3.Prefix' => s3_prefix,
|
663
|
-
}
|
664
|
-
link = generate_request("BundleInstance", params)
|
665
|
-
request_info(link, QEc2BundleInstanceParser.new)
|
666
|
-
rescue Exception
|
667
|
-
on_exception
|
668
|
-
end
|
669
|
-
|
670
|
-
# Describe the status of the Windows AMI bundlings.
|
671
|
-
# If +list+ is omitted the returns the whole list of tasks.
|
672
|
-
#
|
673
|
-
# ec2.describe_bundle_tasks(['bun-4fa74226']) #=>
|
674
|
-
# [{:s3_bucket => "my-awesome-bucket"
|
675
|
-
# :aws_id => "bun-0fa70206",
|
676
|
-
# :s3_prefix => "win1pr",
|
677
|
-
# :aws_start_time => "2008-10-14T16:27:57.000Z",
|
678
|
-
# :aws_update_time => "2008-10-14T16:37:10.000Z",
|
679
|
-
# :aws_error_code => "Client.S3Error",
|
680
|
-
# :aws_error_message =>
|
681
|
-
# "AccessDenied(403)- Invalid according to Policy: Policy Condition failed: [\"eq\", \"$acl\", \"aws-exec-read\"]",
|
682
|
-
# :aws_state => "failed",
|
683
|
-
# :aws_instance_id => "i-e3e24e8a"}]
|
684
|
-
#
|
685
|
-
def describe_bundle_tasks(list=[])
|
686
|
-
link = generate_request("DescribeBundleTasks", hash_params('BundleId', list.to_a))
|
687
|
-
request_info(link, QEc2DescribeBundleTasksParser.new)
|
688
|
-
rescue Exception
|
689
|
-
on_exception
|
690
|
-
end
|
691
|
-
|
692
|
-
# Cancel an in‐progress or pending bundle task by id.
|
693
|
-
#
|
694
|
-
# ec2.cancel_bundle_task('bun-73a7421a') #=>
|
695
|
-
# [{:s3_bucket => "my-awesome-bucket"
|
696
|
-
# :aws_id => "bun-0fa70206",
|
697
|
-
# :s3_prefix => "win02",
|
698
|
-
# :aws_start_time => "2008-10-14T13:00:29.000Z",
|
699
|
-
# :aws_error_message => "User has requested bundling operation cancellation",
|
700
|
-
# :aws_state => "failed",
|
701
|
-
# :aws_update_time => "2008-10-14T13:01:31.000Z",
|
702
|
-
# :aws_error_code => "Client.Cancelled",
|
703
|
-
# :aws_instance_id => "i-e3e24e8a"}
|
704
|
-
#
|
705
|
-
def cancel_bundle_task(bundle_id)
|
706
|
-
link = generate_request("CancelBundleTask", { 'BundleId' => bundle_id })
|
707
|
-
request_info(link, QEc2BundleInstanceParser.new)
|
708
|
-
rescue Exception
|
709
|
-
on_exception
|
710
|
-
end
|
711
|
-
|
712
|
-
#-----------------------------------------------------------------
|
713
|
-
# Security groups
|
714
|
-
#-----------------------------------------------------------------
|
715
|
-
|
716
|
-
# Retrieve Security Group information. If +list+ is omitted the returns the whole list of groups.
|
717
|
-
#
|
718
|
-
# ec2.describe_security_groups #=>
|
719
|
-
# [{:aws_group_name => "default-1",
|
720
|
-
# :aws_owner => "000000000888",
|
721
|
-
# :aws_description => "Default allowing SSH, HTTP, and HTTPS ingress",
|
722
|
-
# :aws_perms =>
|
723
|
-
# [{:owner => "000000000888", :group => "default"},
|
724
|
-
# {:owner => "000000000888", :group => "default-1"},
|
725
|
-
# {:to_port => "-1", :protocol => "icmp", :from_port => "-1", :cidr_ips => "0.0.0.0/0"},
|
726
|
-
# {:to_port => "22", :protocol => "tcp", :from_port => "22", :cidr_ips => "0.0.0.0/0"},
|
727
|
-
# {:to_port => "80", :protocol => "tcp", :from_port => "80", :cidr_ips => "0.0.0.0/0"},
|
728
|
-
# {:to_port => "443", :protocol => "tcp", :from_port => "443", :cidr_ips => "0.0.0.0/0"}]},
|
729
|
-
# ..., {...}]
|
730
|
-
#
|
731
|
-
def describe_security_groups(list=[])
|
732
|
-
link = generate_request("DescribeSecurityGroups", hash_params('GroupName',list.to_a))
|
733
|
-
request_cache_or_info( :describe_security_groups, link, QEc2DescribeSecurityGroupsParser, @@bench, list.blank?) do |parser|
|
734
|
-
result = []
|
735
|
-
parser.result.each do |item|
|
736
|
-
perms = []
|
737
|
-
item.ipPermissions.each do |perm|
|
738
|
-
perm.groups.each do |ngroup|
|
739
|
-
perms << {:group => ngroup.groupName,
|
740
|
-
:owner => ngroup.userId}
|
741
|
-
end
|
742
|
-
perm.ipRanges.each do |cidr_ip|
|
743
|
-
perms << {:from_port => perm.fromPort,
|
744
|
-
:to_port => perm.toPort,
|
745
|
-
:protocol => perm.ipProtocol,
|
746
|
-
:cidr_ips => cidr_ip}
|
747
|
-
end
|
748
|
-
end
|
749
|
-
|
750
|
-
# delete duplication
|
751
|
-
perms.each_index do |i|
|
752
|
-
(0...i).each do |j|
|
753
|
-
if perms[i] == perms[j] then perms[i] = nil; break; end
|
754
|
-
end
|
755
|
-
end
|
756
|
-
perms.compact!
|
757
|
-
|
758
|
-
result << {:aws_owner => item.ownerId,
|
759
|
-
:aws_group_name => item.groupName,
|
760
|
-
:aws_description => item.groupDescription,
|
761
|
-
:aws_perms => perms}
|
762
|
-
|
763
|
-
end
|
764
|
-
result
|
765
|
-
end
|
766
|
-
rescue Exception
|
767
|
-
on_exception
|
768
|
-
end
|
769
|
-
|
770
|
-
# Create new Security Group. Returns +true+ or an exception.
|
771
|
-
#
|
772
|
-
# ec2.create_security_group('default-1',"Default allowing SSH, HTTP, and HTTPS ingress") #=> true
|
773
|
-
#
|
774
|
-
def create_security_group(name, description)
|
775
|
-
# EC2 doesn't like an empty description...
|
776
|
-
description = " " if description.blank?
|
777
|
-
link = generate_request("CreateSecurityGroup",
|
778
|
-
'GroupName' => name.to_s,
|
779
|
-
'GroupDescription' => description.to_s)
|
780
|
-
request_info(link, RightBoolResponseParser.new(:logger => @logger))
|
781
|
-
rescue Exception
|
782
|
-
on_exception
|
783
|
-
end
|
784
|
-
|
785
|
-
# Remove Security Group. Returns +true+ or an exception.
|
786
|
-
#
|
787
|
-
# ec2.delete_security_group('default-1') #=> true
|
788
|
-
#
|
789
|
-
def delete_security_group(name)
|
790
|
-
link = generate_request("DeleteSecurityGroup",
|
791
|
-
'GroupName' => name.to_s)
|
792
|
-
request_info(link, RightBoolResponseParser.new(:logger => @logger))
|
793
|
-
rescue Exception
|
794
|
-
on_exception
|
795
|
-
end
|
796
|
-
|
797
|
-
# Authorize named ingress for security group. Allows instances that are member of someone
|
798
|
-
# else's security group to open connections to instances in my group.
|
799
|
-
#
|
800
|
-
# ec2.authorize_security_group_named_ingress('my_awesome_group', '7011-0219-8268', 'their_group_name') #=> true
|
801
|
-
#
|
802
|
-
def authorize_security_group_named_ingress(name, owner, group)
|
803
|
-
link = generate_request("AuthorizeSecurityGroupIngress",
|
804
|
-
'GroupName' => name.to_s,
|
805
|
-
'SourceSecurityGroupName' => group.to_s,
|
806
|
-
'SourceSecurityGroupOwnerId' => owner.to_s.gsub(/-/,''))
|
807
|
-
request_info(link, RightBoolResponseParser.new(:logger => @logger))
|
808
|
-
rescue Exception
|
809
|
-
on_exception
|
810
|
-
end
|
811
|
-
|
812
|
-
# Revoke named ingress for security group.
|
813
|
-
#
|
814
|
-
# ec2.revoke_security_group_named_ingress('my_awesome_group', aws_user_id, 'another_group_name') #=> true
|
815
|
-
#
|
816
|
-
def revoke_security_group_named_ingress(name, owner, group)
|
817
|
-
link = generate_request("RevokeSecurityGroupIngress",
|
818
|
-
'GroupName' => name.to_s,
|
819
|
-
'SourceSecurityGroupName' => group.to_s,
|
820
|
-
'SourceSecurityGroupOwnerId' => owner.to_s.gsub(/-/,''))
|
821
|
-
request_info(link, RightBoolResponseParser.new(:logger => @logger))
|
822
|
-
rescue Exception
|
823
|
-
on_exception
|
824
|
-
end
|
825
|
-
|
826
|
-
# Add permission to a security group. Returns +true+ or an exception. +protocol+ is one of :'tcp'|'udp'|'icmp'.
|
827
|
-
#
|
828
|
-
# ec2.authorize_security_group_IP_ingress('my_awesome_group', 80, 82, 'udp', '192.168.1.0/8') #=> true
|
829
|
-
# ec2.authorize_security_group_IP_ingress('my_awesome_group', -1, -1, 'icmp') #=> true
|
830
|
-
#
|
831
|
-
def authorize_security_group_IP_ingress(name, from_port, to_port, protocol='tcp', cidr_ip='0.0.0.0/0')
|
832
|
-
link = generate_request("AuthorizeSecurityGroupIngress",
|
833
|
-
'GroupName' => name.to_s,
|
834
|
-
'IpProtocol' => protocol.to_s,
|
835
|
-
'FromPort' => from_port.to_s,
|
836
|
-
'ToPort' => to_port.to_s,
|
837
|
-
'CidrIp' => cidr_ip.to_s)
|
838
|
-
request_info(link, RightBoolResponseParser.new(:logger => @logger))
|
839
|
-
rescue Exception
|
840
|
-
on_exception
|
841
|
-
end
|
842
|
-
|
843
|
-
# Remove permission from a security group. Returns +true+ or an exception. +protocol+ is one of :'tcp'|'udp'|'icmp' ('tcp' is default).
|
844
|
-
#
|
845
|
-
# ec2.revoke_security_group_IP_ingress('my_awesome_group', 80, 82, 'udp', '192.168.1.0/8') #=> true
|
846
|
-
#
|
847
|
-
def revoke_security_group_IP_ingress(name, from_port, to_port, protocol='tcp', cidr_ip='0.0.0.0/0')
|
848
|
-
link = generate_request("RevokeSecurityGroupIngress",
|
849
|
-
'GroupName' => name.to_s,
|
850
|
-
'IpProtocol' => protocol.to_s,
|
851
|
-
'FromPort' => from_port.to_s,
|
852
|
-
'ToPort' => to_port.to_s,
|
853
|
-
'CidrIp' => cidr_ip.to_s)
|
854
|
-
request_info(link, RightBoolResponseParser.new(:logger => @logger))
|
855
|
-
rescue Exception
|
856
|
-
on_exception
|
139
|
+
request_info_impl(:ec2_connection, @@bench, request, parser)
|
857
140
|
end
|
858
141
|
|
859
142
|
#-----------------------------------------------------------------
|
@@ -868,9 +151,10 @@ module RightAws
|
|
868
151
|
# {: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"},
|
869
152
|
# ..., {...} ]
|
870
153
|
#
|
871
|
-
def describe_key_pairs(
|
872
|
-
|
873
|
-
|
154
|
+
def describe_key_pairs(*key_pairs)
|
155
|
+
key_pairs = key_pairs.flatten
|
156
|
+
link = generate_request("DescribeKeyPairs", amazonize_list('KeyName', key_pairs))
|
157
|
+
request_cache_or_info :describe_key_pairs, link, QEc2DescribeKeyPairParser, @@bench, key_pairs.blank?
|
874
158
|
rescue Exception
|
875
159
|
on_exception
|
876
160
|
end
|
@@ -940,10 +224,10 @@ module RightAws
|
|
940
224
|
#
|
941
225
|
# ec2.describe_addresses('75.101.154.140') #=> [{:instance_id=>"i-d630cbbf", :public_ip=>"75.101.154.140"}]
|
942
226
|
#
|
943
|
-
def describe_addresses(
|
944
|
-
|
945
|
-
|
946
|
-
request_cache_or_info :describe_addresses, link, QEc2DescribeAddressesParser, @@bench,
|
227
|
+
def describe_addresses(*addresses)
|
228
|
+
addresses = addresses.flatten
|
229
|
+
link = generate_request("DescribeAddresses", amazonize_list('PublicIp', addresses))
|
230
|
+
request_cache_or_info :describe_addresses, link, QEc2DescribeAddressesParser, @@bench, addresses.blank?
|
947
231
|
rescue Exception
|
948
232
|
on_exception
|
949
233
|
end
|
@@ -989,10 +273,10 @@ module RightAws
|
|
989
273
|
# :zone_state=>"available",
|
990
274
|
# :zone_name=>"us-east-1c"}]
|
991
275
|
#
|
992
|
-
def describe_availability_zones(
|
993
|
-
|
994
|
-
|
995
|
-
request_cache_or_info :describe_availability_zones, link, QEc2DescribeAvailabilityZonesParser, @@bench,
|
276
|
+
def describe_availability_zones(*availability_zones)
|
277
|
+
availability_zones = availability_zones.flatten
|
278
|
+
link = generate_request("DescribeAvailabilityZones", amazonize_list('ZoneName', availability_zones))
|
279
|
+
request_cache_or_info :describe_availability_zones, link, QEc2DescribeAvailabilityZonesParser, @@bench, availability_zones.blank?
|
996
280
|
rescue Exception
|
997
281
|
on_exception
|
998
282
|
end
|
@@ -1005,227 +289,14 @@ module RightAws
|
|
1005
289
|
#
|
1006
290
|
# ec2.describe_regions #=> ["eu-west-1", "us-east-1"]
|
1007
291
|
#
|
1008
|
-
def describe_regions(
|
1009
|
-
|
1010
|
-
|
1011
|
-
request_cache_or_info :describe_regions, link, QEc2DescribeRegionsParser, @@bench,
|
1012
|
-
rescue Exception
|
1013
|
-
on_exception
|
1014
|
-
end
|
1015
|
-
|
1016
|
-
|
1017
|
-
#-----------------------------------------------------------------
|
1018
|
-
# EBS: Volumes
|
1019
|
-
#-----------------------------------------------------------------
|
1020
|
-
|
1021
|
-
# Describe all EBS volumes.
|
1022
|
-
#
|
1023
|
-
# ec2.describe_volumes #=>
|
1024
|
-
# [{:aws_size => 94,
|
1025
|
-
# :aws_device => "/dev/sdc",
|
1026
|
-
# :aws_attachment_status => "attached",
|
1027
|
-
# :zone => "merlot",
|
1028
|
-
# :snapshot_id => nil,
|
1029
|
-
# :aws_attached_at => Wed Jun 18 08:19:28 UTC 2008,
|
1030
|
-
# :aws_status => "in-use",
|
1031
|
-
# :aws_id => "vol-60957009",
|
1032
|
-
# :aws_created_at => Wed Jun 18 08:19:20s UTC 2008,
|
1033
|
-
# :aws_instance_id => "i-c014c0a9"},
|
1034
|
-
# {:aws_size => 1,
|
1035
|
-
# :zone => "merlot",
|
1036
|
-
# :snapshot_id => nil,
|
1037
|
-
# :aws_status => "available",
|
1038
|
-
# :aws_id => "vol-58957031",
|
1039
|
-
# :aws_created_at => Wed Jun 18 08:19:21 UTC 2008,}, ... ]
|
1040
|
-
#
|
1041
|
-
def describe_volumes(list=[])
|
1042
|
-
link = generate_request("DescribeVolumes",
|
1043
|
-
hash_params('VolumeId',list.to_a))
|
1044
|
-
request_cache_or_info :describe_volumes, link, QEc2DescribeVolumesParser, @@bench, list.blank?
|
1045
|
-
rescue Exception
|
1046
|
-
on_exception
|
1047
|
-
end
|
1048
|
-
|
1049
|
-
# Create new EBS volume based on previously created snapshot.
|
1050
|
-
# +Size+ in Gigabytes.
|
1051
|
-
#
|
1052
|
-
# ec2.create_volume('snap-000000', 10, zone) #=>
|
1053
|
-
# {:snapshot_id => "snap-e21df98b",
|
1054
|
-
# :aws_status => "creating",
|
1055
|
-
# :aws_id => "vol-fc9f7a95",
|
1056
|
-
# :zone => "merlot",
|
1057
|
-
# :aws_created_at => Tue Jun 24 18:13:32 UTC 2008,
|
1058
|
-
# :aws_size => 94}
|
1059
|
-
#
|
1060
|
-
def create_volume(snapshot_id, size, zone)
|
1061
|
-
link = generate_request("CreateVolume",
|
1062
|
-
"SnapshotId" => snapshot_id.to_s,
|
1063
|
-
"Size" => size.to_s,
|
1064
|
-
"AvailabilityZone" => zone.to_s )
|
1065
|
-
request_info(link, QEc2CreateVolumeParser.new(:logger => @logger))
|
1066
|
-
rescue Exception
|
1067
|
-
on_exception
|
1068
|
-
end
|
1069
|
-
|
1070
|
-
# Delete the specified EBS volume.
|
1071
|
-
# This does not deletes any snapshots created from this volume.
|
1072
|
-
#
|
1073
|
-
# ec2.delete_volume('vol-b48a6fdd') #=> true
|
1074
|
-
#
|
1075
|
-
def delete_volume(volume_id)
|
1076
|
-
link = generate_request("DeleteVolume",
|
1077
|
-
"VolumeId" => volume_id.to_s)
|
1078
|
-
request_info(link, RightBoolResponseParser.new(:logger => @logger))
|
1079
|
-
rescue Exception
|
1080
|
-
on_exception
|
1081
|
-
end
|
1082
|
-
|
1083
|
-
# Attach the specified EBS volume to a specified instance, exposing the
|
1084
|
-
# volume using the specified device name.
|
1085
|
-
#
|
1086
|
-
# ec2.attach_volume('vol-898a6fe0', 'i-7c905415', '/dev/sdh') #=>
|
1087
|
-
# { :aws_instance_id => "i-7c905415",
|
1088
|
-
# :aws_device => "/dev/sdh",
|
1089
|
-
# :aws_status => "attaching",
|
1090
|
-
# :aws_attached_at => "2008-03-28T14:14:39.000Z",
|
1091
|
-
# :aws_id => "vol-898a6fe0" }
|
1092
|
-
#
|
1093
|
-
def attach_volume(volume_id, instance_id, device)
|
1094
|
-
link = generate_request("AttachVolume",
|
1095
|
-
"VolumeId" => volume_id.to_s,
|
1096
|
-
"InstanceId" => instance_id.to_s,
|
1097
|
-
"Device" => device.to_s)
|
1098
|
-
request_info(link, QEc2AttachAndDetachVolumeParser.new(:logger => @logger))
|
1099
|
-
rescue Exception
|
1100
|
-
on_exception
|
1101
|
-
end
|
1102
|
-
|
1103
|
-
# Detach the specified EBS volume from the instance to which it is attached.
|
1104
|
-
#
|
1105
|
-
# ec2.detach_volume('vol-898a6fe0') #=>
|
1106
|
-
# { :aws_instance_id => "i-7c905415",
|
1107
|
-
# :aws_device => "/dev/sdh",
|
1108
|
-
# :aws_status => "detaching",
|
1109
|
-
# :aws_attached_at => "2008-03-28T14:38:34.000Z",
|
1110
|
-
# :aws_id => "vol-898a6fe0"}
|
1111
|
-
#
|
1112
|
-
def detach_volume(volume_id, instance_id=nil, device=nil, force=nil)
|
1113
|
-
hash = { "VolumeId" => volume_id.to_s }
|
1114
|
-
hash["InstanceId"] = instance_id.to_s unless instance_id.blank?
|
1115
|
-
hash["Device"] = device.to_s unless device.blank?
|
1116
|
-
hash["Force"] = 'true' if force
|
1117
|
-
#
|
1118
|
-
link = generate_request("DetachVolume", hash)
|
1119
|
-
request_info(link, QEc2AttachAndDetachVolumeParser.new(:logger => @logger))
|
292
|
+
def describe_regions(*regions)
|
293
|
+
regions = regions.flatten
|
294
|
+
link = generate_request("DescribeRegions", amazonize_list('RegionName', regions))
|
295
|
+
request_cache_or_info :describe_regions, link, QEc2DescribeRegionsParser, @@bench, regions.blank?
|
1120
296
|
rescue Exception
|
1121
297
|
on_exception
|
1122
298
|
end
|
1123
299
|
|
1124
|
-
|
1125
|
-
#-----------------------------------------------------------------
|
1126
|
-
# EBS: Snapshots
|
1127
|
-
#-----------------------------------------------------------------
|
1128
|
-
|
1129
|
-
# Describe all EBS snapshots.
|
1130
|
-
#
|
1131
|
-
# ec2.describe_snapshots #=>
|
1132
|
-
# [ { :aws_progress => "100%",
|
1133
|
-
# :aws_status => "completed",
|
1134
|
-
# :aws_id => "snap-72a5401b",
|
1135
|
-
# :aws_volume_id => "vol-5582673c",
|
1136
|
-
# :aws_started_at => "2008-02-23T02:50:48.000Z"},
|
1137
|
-
# { :aws_progress => "100%",
|
1138
|
-
# :aws_status => "completed",
|
1139
|
-
# :aws_id => "snap-75a5401c",
|
1140
|
-
# :aws_volume_id => "vol-5582673c",
|
1141
|
-
# :aws_started_at => "2008-02-23T16:23:19.000Z" },...]
|
1142
|
-
#
|
1143
|
-
def describe_snapshots(list=[])
|
1144
|
-
link = generate_request("DescribeSnapshots",
|
1145
|
-
hash_params('SnapshotId',list.to_a))
|
1146
|
-
request_cache_or_info :describe_snapshots, link, QEc2DescribeSnapshotsParser, @@bench, list.blank?
|
1147
|
-
rescue Exception
|
1148
|
-
on_exception
|
1149
|
-
end
|
1150
|
-
|
1151
|
-
# Create a snapshot of specified volume.
|
1152
|
-
#
|
1153
|
-
# ec2.create_snapshot('vol-898a6fe0') #=>
|
1154
|
-
# {:aws_volume_id => "vol-fd9f7a94",
|
1155
|
-
# :aws_started_at => Tue Jun 24 18:40:40 UTC 2008,
|
1156
|
-
# :aws_progress => "",
|
1157
|
-
# :aws_status => "pending",
|
1158
|
-
# :aws_id => "snap-d56783bc"}
|
1159
|
-
#
|
1160
|
-
def create_snapshot(volume_id)
|
1161
|
-
link = generate_request("CreateSnapshot",
|
1162
|
-
"VolumeId" => volume_id.to_s)
|
1163
|
-
request_info(link, QEc2CreateSnapshotParser.new(:logger => @logger))
|
1164
|
-
rescue Exception
|
1165
|
-
on_exception
|
1166
|
-
end
|
1167
|
-
|
1168
|
-
# Create a snapshot of specified volume, but with the normal retry algorithms disabled.
|
1169
|
-
# This method will return immediately upon error. The user can specify connect and read timeouts (in s)
|
1170
|
-
# for the connection to AWS. If the user does not specify timeouts, try_create_snapshot uses the default values
|
1171
|
-
# in Rightscale::HttpConnection.
|
1172
|
-
#
|
1173
|
-
# ec2.try_create_snapshot('vol-898a6fe0') #=>
|
1174
|
-
# {:aws_volume_id => "vol-fd9f7a94",
|
1175
|
-
# :aws_started_at => Tue Jun 24 18:40:40 UTC 2008,
|
1176
|
-
# :aws_progress => "",
|
1177
|
-
# :aws_status => "pending",
|
1178
|
-
# :aws_id => "snap-d56783bc"}
|
1179
|
-
#
|
1180
|
-
def try_create_snapshot(volume_id, connect_timeout = nil, read_timeout = nil)
|
1181
|
-
# For safety in the ensure block...we don't want to restore values
|
1182
|
-
# if we never read them in the first place
|
1183
|
-
orig_reiteration_time = nil
|
1184
|
-
orig_http_params = nil
|
1185
|
-
|
1186
|
-
orig_reiteration_time = RightAws::AWSErrorHandler::reiteration_time
|
1187
|
-
RightAws::AWSErrorHandler::reiteration_time = 0
|
1188
|
-
|
1189
|
-
orig_http_params = Rightscale::HttpConnection::params()
|
1190
|
-
new_http_params = orig_http_params.dup
|
1191
|
-
new_http_params[:http_connection_retry_count] = 0
|
1192
|
-
new_http_params[:http_connection_open_timeout] = connect_timeout if !connect_timeout.nil?
|
1193
|
-
new_http_params[:http_connection_read_timeout] = read_timeout if !read_timeout.nil?
|
1194
|
-
Rightscale::HttpConnection::params = new_http_params
|
1195
|
-
|
1196
|
-
link = generate_request("CreateSnapshot",
|
1197
|
-
"VolumeId" => volume_id.to_s)
|
1198
|
-
request_info(link, QEc2CreateSnapshotParser.new(:logger => @logger))
|
1199
|
-
|
1200
|
-
rescue Exception
|
1201
|
-
on_exception
|
1202
|
-
ensure
|
1203
|
-
RightAws::AWSErrorHandler::reiteration_time = orig_reiteration_time if orig_reiteration_time
|
1204
|
-
Rightscale::HttpConnection::params = orig_http_params if orig_http_params
|
1205
|
-
end
|
1206
|
-
|
1207
|
-
# Delete the specified snapshot.
|
1208
|
-
#
|
1209
|
-
# ec2.delete_snapshot('snap-55a5403c') #=> true
|
1210
|
-
#
|
1211
|
-
def delete_snapshot(snapshot_id)
|
1212
|
-
link = generate_request("DeleteSnapshot",
|
1213
|
-
"SnapshotId" => snapshot_id.to_s)
|
1214
|
-
request_info(link, RightBoolResponseParser.new(:logger => @logger))
|
1215
|
-
rescue Exception
|
1216
|
-
on_exception
|
1217
|
-
end
|
1218
|
-
|
1219
|
-
#-----------------------------------------------------------------
|
1220
|
-
# PARSERS: Boolean Response Parser
|
1221
|
-
#-----------------------------------------------------------------
|
1222
|
-
|
1223
|
-
class RightBoolResponseParser < RightAWSParser #:nodoc:
|
1224
|
-
def tagend(name)
|
1225
|
-
@result = @text=='true' ? true : false if name == 'return'
|
1226
|
-
end
|
1227
|
-
end
|
1228
|
-
|
1229
300
|
#-----------------------------------------------------------------
|
1230
301
|
# PARSERS: Key Pair
|
1231
302
|
#-----------------------------------------------------------------
|
@@ -1259,308 +330,6 @@ module RightAws
|
|
1259
330
|
end
|
1260
331
|
end
|
1261
332
|
|
1262
|
-
#-----------------------------------------------------------------
|
1263
|
-
# PARSERS: Security Groups
|
1264
|
-
#-----------------------------------------------------------------
|
1265
|
-
|
1266
|
-
class QEc2UserIdGroupPairType #:nodoc:
|
1267
|
-
attr_accessor :userId
|
1268
|
-
attr_accessor :groupName
|
1269
|
-
end
|
1270
|
-
|
1271
|
-
class QEc2IpPermissionType #:nodoc:
|
1272
|
-
attr_accessor :ipProtocol
|
1273
|
-
attr_accessor :fromPort
|
1274
|
-
attr_accessor :toPort
|
1275
|
-
attr_accessor :groups
|
1276
|
-
attr_accessor :ipRanges
|
1277
|
-
end
|
1278
|
-
|
1279
|
-
class QEc2SecurityGroupItemType #:nodoc:
|
1280
|
-
attr_accessor :groupName
|
1281
|
-
attr_accessor :groupDescription
|
1282
|
-
attr_accessor :ownerId
|
1283
|
-
attr_accessor :ipPermissions
|
1284
|
-
end
|
1285
|
-
|
1286
|
-
|
1287
|
-
class QEc2DescribeSecurityGroupsParser < RightAWSParser #:nodoc:
|
1288
|
-
def tagstart(name, attributes)
|
1289
|
-
case name
|
1290
|
-
when 'item'
|
1291
|
-
if @xmlpath=='DescribeSecurityGroupsResponse/securityGroupInfo'
|
1292
|
-
@group = QEc2SecurityGroupItemType.new
|
1293
|
-
@group.ipPermissions = []
|
1294
|
-
elsif @xmlpath=='DescribeSecurityGroupsResponse/securityGroupInfo/item/ipPermissions'
|
1295
|
-
@perm = QEc2IpPermissionType.new
|
1296
|
-
@perm.ipRanges = []
|
1297
|
-
@perm.groups = []
|
1298
|
-
elsif @xmlpath=='DescribeSecurityGroupsResponse/securityGroupInfo/item/ipPermissions/item/groups'
|
1299
|
-
@sgroup = QEc2UserIdGroupPairType.new
|
1300
|
-
end
|
1301
|
-
end
|
1302
|
-
end
|
1303
|
-
def tagend(name)
|
1304
|
-
case name
|
1305
|
-
when 'ownerId' then @group.ownerId = @text
|
1306
|
-
when 'groupDescription' then @group.groupDescription = @text
|
1307
|
-
when 'groupName'
|
1308
|
-
if @xmlpath=='DescribeSecurityGroupsResponse/securityGroupInfo/item'
|
1309
|
-
@group.groupName = @text
|
1310
|
-
elsif @xmlpath=='DescribeSecurityGroupsResponse/securityGroupInfo/item/ipPermissions/item/groups/item'
|
1311
|
-
@sgroup.groupName = @text
|
1312
|
-
end
|
1313
|
-
when 'ipProtocol' then @perm.ipProtocol = @text
|
1314
|
-
when 'fromPort' then @perm.fromPort = @text
|
1315
|
-
when 'toPort' then @perm.toPort = @text
|
1316
|
-
when 'userId' then @sgroup.userId = @text
|
1317
|
-
when 'cidrIp' then @perm.ipRanges << @text
|
1318
|
-
when 'item'
|
1319
|
-
if @xmlpath=='DescribeSecurityGroupsResponse/securityGroupInfo/item/ipPermissions/item/groups'
|
1320
|
-
@perm.groups << @sgroup
|
1321
|
-
elsif @xmlpath=='DescribeSecurityGroupsResponse/securityGroupInfo/item/ipPermissions'
|
1322
|
-
@group.ipPermissions << @perm
|
1323
|
-
elsif @xmlpath=='DescribeSecurityGroupsResponse/securityGroupInfo'
|
1324
|
-
@result << @group
|
1325
|
-
end
|
1326
|
-
end
|
1327
|
-
end
|
1328
|
-
def reset
|
1329
|
-
@result = []
|
1330
|
-
end
|
1331
|
-
end
|
1332
|
-
|
1333
|
-
#-----------------------------------------------------------------
|
1334
|
-
# PARSERS: Images
|
1335
|
-
#-----------------------------------------------------------------
|
1336
|
-
|
1337
|
-
class QEc2DescribeImagesParser < RightAWSParser #:nodoc:
|
1338
|
-
def tagstart(name, attributes)
|
1339
|
-
if name == 'item' && @xmlpath[%r{.*/imagesSet$}]
|
1340
|
-
@image = {}
|
1341
|
-
end
|
1342
|
-
end
|
1343
|
-
def tagend(name)
|
1344
|
-
case name
|
1345
|
-
when 'imageId' then @image[:aws_id] = @text
|
1346
|
-
when 'imageLocation' then @image[:aws_location] = @text
|
1347
|
-
when 'imageState' then @image[:aws_state] = @text
|
1348
|
-
when 'imageOwnerId' then @image[:aws_owner] = @text
|
1349
|
-
when 'isPublic' then @image[:aws_is_public]= @text == 'true' ? true : false
|
1350
|
-
when 'productCode' then (@image[:aws_product_codes] ||= []) << @text
|
1351
|
-
when 'architecture' then @image[:aws_architecture] = @text
|
1352
|
-
when 'imageType' then @image[:aws_image_type] = @text
|
1353
|
-
when 'kernelId' then @image[:aws_kernel_id] = @text
|
1354
|
-
when 'ramdiskId' then @image[:aws_ramdisk_id] = @text
|
1355
|
-
when 'item' then @result << @image if @xmlpath[%r{.*/imagesSet$}]
|
1356
|
-
end
|
1357
|
-
end
|
1358
|
-
def reset
|
1359
|
-
@result = []
|
1360
|
-
end
|
1361
|
-
end
|
1362
|
-
|
1363
|
-
class QEc2RegisterImageParser < RightAWSParser #:nodoc:
|
1364
|
-
def tagend(name)
|
1365
|
-
@result = @text if name == 'imageId'
|
1366
|
-
end
|
1367
|
-
end
|
1368
|
-
|
1369
|
-
#-----------------------------------------------------------------
|
1370
|
-
# PARSERS: Image Attribute
|
1371
|
-
#-----------------------------------------------------------------
|
1372
|
-
|
1373
|
-
class QEc2DescribeImageAttributeParser < RightAWSParser #:nodoc:
|
1374
|
-
def tagstart(name, attributes)
|
1375
|
-
case name
|
1376
|
-
when 'launchPermission'
|
1377
|
-
@result[:groups] = []
|
1378
|
-
@result[:users] = []
|
1379
|
-
when 'productCodes'
|
1380
|
-
@result[:aws_product_codes] = []
|
1381
|
-
end
|
1382
|
-
end
|
1383
|
-
def tagend(name)
|
1384
|
-
# right now only 'launchPermission' is supported by Amazon.
|
1385
|
-
# But nobody know what will they xml later as attribute. That is why we
|
1386
|
-
# check for 'group' and 'userId' inside of 'launchPermission/item'
|
1387
|
-
case name
|
1388
|
-
when 'imageId' then @result[:aws_id] = @text
|
1389
|
-
when 'group' then @result[:groups] << @text if @xmlpath == 'DescribeImageAttributeResponse/launchPermission/item'
|
1390
|
-
when 'userId' then @result[:users] << @text if @xmlpath == 'DescribeImageAttributeResponse/launchPermission/item'
|
1391
|
-
when 'productCode' then @result[:aws_product_codes] << @text
|
1392
|
-
when 'kernel' then @result[:aws_kernel] = @text
|
1393
|
-
when 'ramdisk' then @result[:aws_ramdisk] = @text
|
1394
|
-
when 'blockDeviceMapping' then @result[:block_device_mapping] = @text
|
1395
|
-
end
|
1396
|
-
end
|
1397
|
-
def reset
|
1398
|
-
@result = {}
|
1399
|
-
end
|
1400
|
-
end
|
1401
|
-
|
1402
|
-
#-----------------------------------------------------------------
|
1403
|
-
# PARSERS: Instances
|
1404
|
-
#-----------------------------------------------------------------
|
1405
|
-
|
1406
|
-
class QEc2DescribeInstancesParser < RightAWSParser #:nodoc:
|
1407
|
-
def tagstart(name, attributes)
|
1408
|
-
# DescribeInstances property
|
1409
|
-
if (name == 'item' && @xmlpath == 'DescribeInstancesResponse/reservationSet') ||
|
1410
|
-
# RunInstances property
|
1411
|
-
(name == 'RunInstancesResponse')
|
1412
|
-
@reservation = { :aws_groups => [],
|
1413
|
-
:instances_set => [] }
|
1414
|
-
|
1415
|
-
elsif (name == 'item') &&
|
1416
|
-
# DescribeInstances property
|
1417
|
-
( @xmlpath=='DescribeInstancesResponse/reservationSet/item/instancesSet' ||
|
1418
|
-
# RunInstances property
|
1419
|
-
@xmlpath=='RunInstancesResponse/instancesSet' )
|
1420
|
-
# the optional params (sometimes are missing and we dont want them to be nil)
|
1421
|
-
@instance = { :aws_reason => '',
|
1422
|
-
:dns_name => '',
|
1423
|
-
:private_dns_name => '',
|
1424
|
-
:ami_launch_index => '',
|
1425
|
-
:ssh_key_name => '',
|
1426
|
-
:aws_state => '',
|
1427
|
-
:aws_product_codes => [] }
|
1428
|
-
end
|
1429
|
-
end
|
1430
|
-
def tagend(name)
|
1431
|
-
case name
|
1432
|
-
# reservation
|
1433
|
-
when 'reservationId' then @reservation[:aws_reservation_id] = @text
|
1434
|
-
when 'ownerId' then @reservation[:aws_owner] = @text
|
1435
|
-
when 'groupId' then @reservation[:aws_groups] << @text
|
1436
|
-
# instance
|
1437
|
-
when 'instanceId' then @instance[:aws_instance_id] = @text
|
1438
|
-
when 'imageId' then @instance[:aws_image_id] = @text
|
1439
|
-
when 'dnsName' then @instance[:dns_name] = @text
|
1440
|
-
when 'privateDnsName' then @instance[:private_dns_name] = @text
|
1441
|
-
when 'reason' then @instance[:aws_reason] = @text
|
1442
|
-
when 'keyName' then @instance[:ssh_key_name] = @text
|
1443
|
-
when 'amiLaunchIndex' then @instance[:ami_launch_index] = @text
|
1444
|
-
when 'code' then @instance[:aws_state_code] = @text
|
1445
|
-
when 'name' then @instance[:aws_state] = @text
|
1446
|
-
when 'productCode' then @instance[:aws_product_codes] << @text
|
1447
|
-
when 'instanceType' then @instance[:aws_instance_type] = @text
|
1448
|
-
when 'launchTime' then @instance[:aws_launch_time] = @text
|
1449
|
-
when 'kernelId' then @instance[:aws_kernel_id] = @text
|
1450
|
-
when 'ramdiskId' then @instance[:aws_ramdisk_id] = @text
|
1451
|
-
when 'platform' then @instance[:aws_platform] = @text
|
1452
|
-
when 'availabilityZone' then @instance[:aws_availability_zone] = @text
|
1453
|
-
when 'item'
|
1454
|
-
if @xmlpath == 'DescribeInstancesResponse/reservationSet/item/instancesSet' || # DescribeInstances property
|
1455
|
-
@xmlpath == 'RunInstancesResponse/instancesSet' # RunInstances property
|
1456
|
-
@reservation[:instances_set] << @instance
|
1457
|
-
elsif @xmlpath=='DescribeInstancesResponse/reservationSet' # DescribeInstances property
|
1458
|
-
@result << @reservation
|
1459
|
-
end
|
1460
|
-
when 'RunInstancesResponse' then @result << @reservation # RunInstances property
|
1461
|
-
end
|
1462
|
-
end
|
1463
|
-
def reset
|
1464
|
-
@result = []
|
1465
|
-
end
|
1466
|
-
end
|
1467
|
-
|
1468
|
-
class QEc2ConfirmProductInstanceParser < RightAWSParser #:nodoc:
|
1469
|
-
def tagend(name)
|
1470
|
-
@result = @text if name == 'ownerId'
|
1471
|
-
end
|
1472
|
-
end
|
1473
|
-
|
1474
|
-
class QEc2TerminateInstancesParser < RightAWSParser #:nodoc:
|
1475
|
-
def tagstart(name, attributes)
|
1476
|
-
@instance = {} if name == 'item'
|
1477
|
-
end
|
1478
|
-
def tagend(name)
|
1479
|
-
case name
|
1480
|
-
when 'instanceId' then @instance[:aws_instance_id] = @text
|
1481
|
-
when 'code'
|
1482
|
-
if @xmlpath == 'TerminateInstancesResponse/instancesSet/item/shutdownState'
|
1483
|
-
@instance[:aws_shutdown_state_code] = @text.to_i
|
1484
|
-
else @instance[:aws_prev_state_code] = @text.to_i end
|
1485
|
-
when 'name'
|
1486
|
-
if @xmlpath == 'TerminateInstancesResponse/instancesSet/item/shutdownState'
|
1487
|
-
@instance[:aws_shutdown_state] = @text
|
1488
|
-
else @instance[:aws_prev_state] = @text end
|
1489
|
-
when 'item' then @result << @instance
|
1490
|
-
end
|
1491
|
-
end
|
1492
|
-
def reset
|
1493
|
-
@result = []
|
1494
|
-
end
|
1495
|
-
end
|
1496
|
-
|
1497
|
-
#-----------------------------------------------------------------
|
1498
|
-
# PARSERS: Console
|
1499
|
-
#-----------------------------------------------------------------
|
1500
|
-
|
1501
|
-
class QEc2GetConsoleOutputParser < RightAWSParser #:nodoc:
|
1502
|
-
def tagend(name)
|
1503
|
-
case name
|
1504
|
-
when 'instanceId' then @result[:aws_instance_id] = @text
|
1505
|
-
when 'timestamp' then @result[:aws_timestamp] = @text
|
1506
|
-
@result[:timestamp] = (Time.parse(@text)).utc
|
1507
|
-
when 'output' then @result[:aws_output] = Base64.decode64(@text)
|
1508
|
-
end
|
1509
|
-
end
|
1510
|
-
def reset
|
1511
|
-
@result = {}
|
1512
|
-
end
|
1513
|
-
end
|
1514
|
-
|
1515
|
-
#-----------------------------------------------------------------
|
1516
|
-
# Instances: Wondows related part
|
1517
|
-
#-----------------------------------------------------------------
|
1518
|
-
class QEc2DescribeBundleTasksParser < RightAWSParser #:nodoc:
|
1519
|
-
def tagstart(name, attributes)
|
1520
|
-
@bundle = {} if name == 'item'
|
1521
|
-
end
|
1522
|
-
def tagend(name)
|
1523
|
-
case name
|
1524
|
-
# when 'requestId' then @bundle[:request_id] = @text
|
1525
|
-
when 'instanceId' then @bundle[:aws_instance_id] = @text
|
1526
|
-
when 'bundleId' then @bundle[:aws_id] = @text
|
1527
|
-
when 'bucket' then @bundle[:s3_bucket] = @text
|
1528
|
-
when 'prefix' then @bundle[:s3_prefix] = @text
|
1529
|
-
when 'startTime' then @bundle[:aws_start_time] = @text
|
1530
|
-
when 'updateTime' then @bundle[:aws_update_time] = @text
|
1531
|
-
when 'state' then @bundle[:aws_state] = @text
|
1532
|
-
when 'progress' then @bundle[:aws_progress] = @text
|
1533
|
-
when 'code' then @bundle[:aws_error_code] = @text
|
1534
|
-
when 'message' then @bundle[:aws_error_message] = @text
|
1535
|
-
when 'item' then @result << @bundle
|
1536
|
-
end
|
1537
|
-
end
|
1538
|
-
def reset
|
1539
|
-
@result = []
|
1540
|
-
end
|
1541
|
-
end
|
1542
|
-
|
1543
|
-
class QEc2BundleInstanceParser < RightAWSParser #:nodoc:
|
1544
|
-
def tagend(name)
|
1545
|
-
case name
|
1546
|
-
# when 'requestId' then @result[:request_id] = @text
|
1547
|
-
when 'instanceId' then @result[:aws_instance_id] = @text
|
1548
|
-
when 'bundleId' then @result[:aws_id] = @text
|
1549
|
-
when 'bucket' then @result[:s3_bucket] = @text
|
1550
|
-
when 'prefix' then @result[:s3_prefix] = @text
|
1551
|
-
when 'startTime' then @result[:aws_start_time] = @text
|
1552
|
-
when 'updateTime' then @result[:aws_update_time] = @text
|
1553
|
-
when 'state' then @result[:aws_state] = @text
|
1554
|
-
when 'progress' then @result[:aws_progress] = @text
|
1555
|
-
when 'code' then @result[:aws_error_code] = @text
|
1556
|
-
when 'message' then @result[:aws_error_message] = @text
|
1557
|
-
end
|
1558
|
-
end
|
1559
|
-
def reset
|
1560
|
-
@result = {}
|
1561
|
-
end
|
1562
|
-
end
|
1563
|
-
|
1564
333
|
#-----------------------------------------------------------------
|
1565
334
|
# PARSERS: Elastic IPs
|
1566
335
|
#-----------------------------------------------------------------
|
@@ -1600,7 +369,7 @@ module RightAws
|
|
1600
369
|
when 'regionName' then @zone[:region_name] = @text
|
1601
370
|
when 'zoneName' then @zone[:zone_name] = @text
|
1602
371
|
when 'zoneState' then @zone[:zone_state] = @text
|
1603
|
-
when 'item'
|
372
|
+
when 'item' then @result << @zone
|
1604
373
|
end
|
1605
374
|
end
|
1606
375
|
def reset
|
@@ -1620,117 +389,6 @@ module RightAws
|
|
1620
389
|
@result = []
|
1621
390
|
end
|
1622
391
|
end
|
1623
|
-
|
1624
|
-
#-----------------------------------------------------------------
|
1625
|
-
# PARSERS: EBS - Volumes
|
1626
|
-
#-----------------------------------------------------------------
|
1627
|
-
|
1628
|
-
class QEc2CreateVolumeParser < RightAWSParser #:nodoc:
|
1629
|
-
def tagend(name)
|
1630
|
-
case name
|
1631
|
-
when 'volumeId' then @result[:aws_id] = @text
|
1632
|
-
when 'status' then @result[:aws_status] = @text
|
1633
|
-
when 'createTime' then @result[:aws_created_at] = Time.parse(@text)
|
1634
|
-
when 'size' then @result[:aws_size] = @text.to_i ###
|
1635
|
-
when 'snapshotId' then @result[:snapshot_id] = @text.blank? ? nil : @text ###
|
1636
|
-
when 'availabilityZone' then @result[:zone] = @text ###
|
1637
|
-
end
|
1638
|
-
end
|
1639
|
-
def reset
|
1640
|
-
@result = {}
|
1641
|
-
end
|
1642
|
-
end
|
1643
|
-
|
1644
|
-
class QEc2AttachAndDetachVolumeParser < RightAWSParser #:nodoc:
|
1645
|
-
def tagend(name)
|
1646
|
-
case name
|
1647
|
-
when 'volumeId' then @result[:aws_id] = @text
|
1648
|
-
when 'instanceId' then @result[:aws_instance_id] = @text
|
1649
|
-
when 'device' then @result[:aws_device] = @text
|
1650
|
-
when 'status' then @result[:aws_attachment_status] = @text
|
1651
|
-
when 'attachTime' then @result[:aws_attached_at] = Time.parse(@text)
|
1652
|
-
end
|
1653
|
-
end
|
1654
|
-
def reset
|
1655
|
-
@result = {}
|
1656
|
-
end
|
1657
|
-
end
|
1658
|
-
|
1659
|
-
class QEc2DescribeVolumesParser < RightAWSParser #:nodoc:
|
1660
|
-
def tagstart(name, attributes)
|
1661
|
-
case name
|
1662
|
-
when 'item'
|
1663
|
-
case @xmlpath
|
1664
|
-
when 'DescribeVolumesResponse/volumeSet' then @volume = {}
|
1665
|
-
end
|
1666
|
-
end
|
1667
|
-
end
|
1668
|
-
def tagend(name)
|
1669
|
-
case name
|
1670
|
-
when 'volumeId'
|
1671
|
-
case @xmlpath
|
1672
|
-
when 'DescribeVolumesResponse/volumeSet/item' then @volume[:aws_id] = @text
|
1673
|
-
end
|
1674
|
-
when 'status'
|
1675
|
-
case @xmlpath
|
1676
|
-
when 'DescribeVolumesResponse/volumeSet/item' then @volume[:aws_status] = @text
|
1677
|
-
when 'DescribeVolumesResponse/volumeSet/item/attachmentSet/item' then @volume[:aws_attachment_status] = @text
|
1678
|
-
end
|
1679
|
-
when 'size' then @volume[:aws_size] = @text.to_i
|
1680
|
-
when 'createTime' then @volume[:aws_created_at] = Time.parse(@text)
|
1681
|
-
when 'instanceId' then @volume[:aws_instance_id] = @text
|
1682
|
-
when 'device' then @volume[:aws_device] = @text
|
1683
|
-
when 'attachTime' then @volume[:aws_attached_at] = Time.parse(@text)
|
1684
|
-
when 'snapshotId' then @volume[:snapshot_id] = @text.blank? ? nil : @text
|
1685
|
-
when 'availabilityZone' then @volume[:zone] = @text
|
1686
|
-
when 'item'
|
1687
|
-
case @xmlpath
|
1688
|
-
when 'DescribeVolumesResponse/volumeSet' then @result << @volume
|
1689
|
-
end
|
1690
|
-
end
|
1691
|
-
end
|
1692
|
-
def reset
|
1693
|
-
@result = []
|
1694
|
-
end
|
1695
|
-
end
|
1696
|
-
|
1697
|
-
#-----------------------------------------------------------------
|
1698
|
-
# PARSERS: EBS - Snapshots
|
1699
|
-
#-----------------------------------------------------------------
|
1700
|
-
|
1701
|
-
class QEc2DescribeSnapshotsParser < RightAWSParser #:nodoc:
|
1702
|
-
def tagstart(name, attributes)
|
1703
|
-
@snapshot = {} if name == 'item'
|
1704
|
-
end
|
1705
|
-
def tagend(name)
|
1706
|
-
case name
|
1707
|
-
when 'volumeId' then @snapshot[:aws_volume_id] = @text
|
1708
|
-
when 'snapshotId' then @snapshot[:aws_id] = @text
|
1709
|
-
when 'status' then @snapshot[:aws_status] = @text
|
1710
|
-
when 'startTime' then @snapshot[:aws_started_at] = Time.parse(@text)
|
1711
|
-
when 'progress' then @snapshot[:aws_progress] = @text
|
1712
|
-
when 'item' then @result << @snapshot
|
1713
|
-
end
|
1714
|
-
end
|
1715
|
-
def reset
|
1716
|
-
@result = []
|
1717
|
-
end
|
1718
|
-
end
|
1719
|
-
|
1720
|
-
class QEc2CreateSnapshotParser < RightAWSParser #:nodoc:
|
1721
|
-
def tagend(name)
|
1722
|
-
case name
|
1723
|
-
when 'volumeId' then @result[:aws_volume_id] = @text
|
1724
|
-
when 'snapshotId' then @result[:aws_id] = @text
|
1725
|
-
when 'status' then @result[:aws_status] = @text
|
1726
|
-
when 'startTime' then @result[:aws_started_at] = Time.parse(@text)
|
1727
|
-
when 'progress' then @result[:aws_progress] = @text
|
1728
|
-
end
|
1729
|
-
end
|
1730
|
-
def reset
|
1731
|
-
@result = {}
|
1732
|
-
end
|
1733
|
-
end
|
1734
392
|
|
1735
393
|
end
|
1736
394
|
|