right_aws 1.10.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. data/History.txt +53 -15
  2. data/Manifest.txt +16 -0
  3. data/README.txt +10 -9
  4. data/Rakefile +13 -15
  5. data/lib/acf/right_acf_interface.rb +224 -118
  6. data/lib/acf/right_acf_origin_access_identities.rb +230 -0
  7. data/lib/acf/right_acf_streaming_interface.rb +236 -0
  8. data/lib/acw/right_acw_interface.rb +249 -0
  9. data/lib/as/right_as_interface.rb +699 -0
  10. data/lib/awsbase/right_awsbase.rb +232 -51
  11. data/lib/awsbase/support.rb +4 -0
  12. data/lib/ec2/right_ec2.rb +33 -1375
  13. data/lib/ec2/right_ec2_ebs.rb +452 -0
  14. data/lib/ec2/right_ec2_images.rb +373 -0
  15. data/lib/ec2/right_ec2_instances.rb +755 -0
  16. data/lib/ec2/right_ec2_monitoring.rb +70 -0
  17. data/lib/ec2/right_ec2_reserved_instances.rb +170 -0
  18. data/lib/ec2/right_ec2_security_groups.rb +280 -0
  19. data/lib/ec2/right_ec2_spot_instances.rb +399 -0
  20. data/lib/ec2/right_ec2_vpc.rb +571 -0
  21. data/lib/elb/right_elb_interface.rb +496 -0
  22. data/lib/rds/right_rds_interface.rb +998 -0
  23. data/lib/right_aws.rb +18 -4
  24. data/lib/s3/right_s3.rb +39 -7
  25. data/lib/s3/right_s3_interface.rb +77 -53
  26. data/lib/sdb/active_sdb.rb +203 -11
  27. data/lib/sdb/right_sdb_interface.rb +68 -45
  28. data/lib/sqs/right_sqs_gen2.rb +73 -16
  29. data/lib/sqs/right_sqs_gen2_interface.rb +131 -51
  30. data/lib/sqs/right_sqs_interface.rb +2 -4
  31. data/test/acf/test_right_acf.rb +10 -18
  32. data/test/rds/test_helper.rb +2 -0
  33. data/test/rds/test_right_rds.rb +120 -0
  34. data/test/s3/test_right_s3.rb +10 -8
  35. data/test/s3/test_right_s3_stubbed.rb +6 -4
  36. data/test/sdb/test_active_sdb.rb +70 -12
  37. data/test/sdb/test_right_sdb.rb +13 -7
  38. data/test/sqs/test_right_sqs_gen2.rb +104 -49
  39. metadata +103 -14
@@ -0,0 +1,399 @@
1
+ #
2
+ # Copyright (c) 2009 RightScale Inc
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ #
23
+
24
+ module RightAws
25
+
26
+ class Ec2
27
+
28
+ #-----------------------------------------------------------------
29
+ # Spot Instances
30
+ #-----------------------------------------------------------------
31
+
32
+ # Describe Spot Price history.
33
+ # Options: :start_time, :end_time, instance_types, product_description
34
+ #
35
+ # ec2.describe_spot_price_history #=>
36
+ # [{:spot_price=>0.054,
37
+ # :timestamp=>"2009-12-07T12:12:58.000Z",
38
+ # :product_description=>"Windows",
39
+ # :instance_type=>"m1.small"},
40
+ # {:spot_price=>0.06,
41
+ # :timestamp=>"2009-12-07T12:18:32.000Z",
42
+ # :product_description=>"Linux/UNIX",
43
+ # :instance_type=>"c1.medium"},
44
+ # {:spot_price=>0.198,
45
+ # :timestamp=>"2009-12-07T12:58:00.000Z",
46
+ # :product_description=>"Windows",
47
+ # :instance_type=>"m1.large"},
48
+ # {:spot_price=>0.028,
49
+ # :timestamp=>"2009-12-07T13:48:50.000Z",
50
+ # :product_description=>"Linux/UNIX",
51
+ # :instance_type=>"m1.small"}, ... ]
52
+ #
53
+ # ec2.describe_spot_price_history(:start_time => 1.day.ago,
54
+ # :end_time => 10.minutes.ago,
55
+ # :instance_types => ["c1.medium", "m1.small"],
56
+ # :product_description => "Linux/UNIX" ) #=>
57
+ # [{:product_description=>"Linux/UNIX",
58
+ # :timestamp=>"2010-02-04T05:44:36.000Z",
59
+ # :spot_price=>0.031,
60
+ # :instance_type=>"m1.small"},
61
+ # {:product_description=>"Linux/UNIX",
62
+ # :timestamp=>"2010-02-04T17:56:25.000Z",
63
+ # :spot_price=>0.058,
64
+ # :instance_type=>"c1.medium"}, ... ]
65
+ #
66
+ def describe_spot_price_history(options={})
67
+ options = options.dup
68
+ request_hash = {}
69
+ request_hash['StartTime'] = AwsUtils::utc_iso8601(options[:start_time]) unless options[:start_time].blank?
70
+ request_hash['EndTime'] = AwsUtils::utc_iso8601(options[:end_time]) unless options[:end_time].blank?
71
+ request_hash['ProductDescription'] = options[:product_description] unless options[:product_description].blank?
72
+ request_hash.merge!(amazonize_list('InstanceType', Array(options[:instance_types]))) unless options[:instance_types].blank?
73
+ link = generate_request("DescribeSpotPriceHistory", request_hash)
74
+ request_info(link, QEc2DescribeSpotPriceHistoryParser.new)
75
+ rescue Exception
76
+ on_exception
77
+ end
78
+
79
+ # Describe Spot Instance requests.
80
+ #
81
+ # ec2.describe_spot_instance_requests #=>
82
+ # [{:type=>"one-time",
83
+ # :create_time=>"2010-03-10T10:30:32.000Z",
84
+ # :instance_type=>"c1.medium",
85
+ # :state=>"cancelled",
86
+ # :groups=>["default"],
87
+ # :product_description=>"Linux/UNIX",
88
+ # :spot_instance_request_id=>"sir-bfa06804",
89
+ # :image_id=>"ami-08f41161",
90
+ # :spot_price=>0.01,
91
+ # :monitoring_enabled=>false},
92
+ # {:type=>"one-time",
93
+ # :create_time=>"2010-03-10T10:33:29.000Z",
94
+ # :instance_type=>"c1.medium",
95
+ # :state=>"open",
96
+ # :groups=>["default", "33"],
97
+ # :product_description=>"Linux/UNIX",
98
+ # :spot_instance_request_id=>"sir-b1713a03",
99
+ # :image_id=>"ami-08f41161",
100
+ # :spot_price=>0.01,
101
+ # :monitoring_enabled=>false,
102
+ # :key_name=>"tim"},
103
+ # {:type=>"one-time",
104
+ # :instance_id=>"i-c516ceae",
105
+ # :create_time=>"2010-03-10T10:43:48.000Z",
106
+ # :instance_type=>"c1.medium",
107
+ # :state=>"active",
108
+ # :groups=>["default", "33"],
109
+ # :product_description=>"Linux/UNIX",
110
+ # :spot_instance_request_id=>"sir-5eb6c604",
111
+ # :image_id=>"ami-08f41161",
112
+ # :spot_price=>0.2,
113
+ # :monitoring_enabled=>false,
114
+ # :key_name=>"tim"}]
115
+ #
116
+ def describe_spot_instance_requests(*spot_instance_request_ids)
117
+ link = generate_request("DescribeSpotInstanceRequests", amazonize_list('SpotInstanceRequestId', spot_instance_request_ids.flatten))
118
+ request_info(link, QEc2DescribeSpotInstanceParser.new(:logger => @logger))
119
+ end
120
+
121
+ # Create a Spot Instance request.
122
+ #
123
+ # Mandatory params: :image_id, :spot_price, :instance_type
124
+ # Optional params: :valid_from, :valid_until, :instance_count, :type, :launch_group,
125
+ # :availability_zone_group, :key_name, :user_data, :addressing_type, :kernel_id,
126
+ # :ramdisk_id, :subnet_id, :availability_zone, :monitoring_enabled, :groups,
127
+ # :block_device_mappings
128
+ #
129
+ # ec2.request_spot_instances(
130
+ # :image_id => 'ami-08f41161',
131
+ # :spot_price => 0.01,
132
+ # :key_name => 'tim',
133
+ # :instance_count => 2,
134
+ # :groups => ['33','default'],
135
+ # :instance_type => 'c1.medium') #=>
136
+ #
137
+ # [{:product_description=>"Linux/UNIX",
138
+ # :type=>"one-time",
139
+ # :spot_instance_requestId=>"sir-7a893003",
140
+ # :monitoring_enabled=>false,
141
+ # :image_id=>"ami-08f41161",
142
+ # :state=>"open",
143
+ # :spot_price=>0.01,
144
+ # :groups=>["default", "33"],
145
+ # :key_name=>"tim",
146
+ # :create_time=>"2010-03-10T10:33:09.000Z",
147
+ # :instance_type=>"c1.medium"},
148
+ # {:product_description=>"Linux/UNIX",
149
+ # :type=>"one-time",
150
+ # :spot_instance_requestId=>"sir-13dc9a03",
151
+ # :monitoring_enabled=>false,
152
+ # :image_id=>"ami-08f41161",
153
+ # :state=>"open",
154
+ # :spot_price=>0.01,
155
+ # :groups=>["default", "33"],
156
+ # :key_name=>"tim",
157
+ # :create_time=>"2010-03-10T10:33:09.000Z",
158
+ # :instance_type=>"c1.medium"}]
159
+ #
160
+ # ec2.request_spot_instances(
161
+ # :image_id => 'ami-08f41161',
162
+ # :spot_price => 0.01,
163
+ # :instance_type => 'm1.small',
164
+ # :valid_from => 10.minutes.since,
165
+ # :valid_until => 1.hour.since,
166
+ # :instance_count => 1,
167
+ # :key_name => 'tim',
168
+ # :groups => ['33','default'],
169
+ # :availability_zone => 'us-east-1a',
170
+ # :monitoring_enabled => true,
171
+ # :launch_group => 'lg1',
172
+ # :availability_zone_group => 'azg1',
173
+ # :block_device_mappings => [ { :device_name => '/dev/sdk',
174
+ # :ebs_snapshot_id => 'snap-145cbc7d',
175
+ # :ebs_delete_on_termination => true,
176
+ # :ebs_volume_size => 3,
177
+ # :virtual_name => 'ephemeral2'
178
+ # } ] ) #=>
179
+ #
180
+ # [{:monitoring_enabled=>true,
181
+ # :type=>"one-time",
182
+ # :image_id=>"ami-08f41161",
183
+ # :launch_group=>"lg1",
184
+ # :state=>"open",
185
+ # :valid_until=>"2010-02-05T19:13:44.000Z",
186
+ # :create_time=>"2010-02-05T18:13:46.000Z",
187
+ # :availability_zone_group=>"azg1",
188
+ # :spot_price=>0.01,
189
+ # :block_device_mappings=>
190
+ # [{:ebs_delete_on_termination=>true,
191
+ # :ebs_volume_size=>3,
192
+ # :virtual_name=>"ephemeral2",
193
+ # :device_name=>"/dev/sdk",
194
+ # :ebs_snapshot_id=>"snap-145cbc7d"}],
195
+ # :instance_type=>"m1.small",
196
+ # :groups=>["default", "33"],
197
+ # :product_description=>"Linux/UNIX",
198
+ # :key_name=>"tim",
199
+ # :valid_from=>"2010-02-05T18:23:44.000Z",
200
+ # :availability_zone=>"us-east-1a",
201
+ # :spot_instance_request_id=>"sir-32da8a03"}]
202
+ #
203
+ def request_spot_instances(options)
204
+ options = options.dup
205
+ request_hash = { 'SpotPrice' => options[:spot_price],
206
+ 'LaunchSpecification.ImageId' => options[:image_id],
207
+ 'LaunchSpecification.InstanceType' => options[:instance_type]}
208
+ request_hash['ValidFrom'] = AwsUtils::utc_iso8601(options[:valid_from]) unless options[:valid_from].blank?
209
+ request_hash['ValidUntil'] = AwsUtils::utc_iso8601(options[:valid_until]) unless options[:valid_until].blank?
210
+ request_hash['InstanceCount'] = options[:instance_count] unless options[:instance_count].blank?
211
+ request_hash['Type'] = options[:type] unless options[:type].blank?
212
+ request_hash['LaunchGroup'] = options[:launch_group] unless options[:launch_group].blank?
213
+ request_hash['AvailabilityZoneGroup'] = options[:availability_zone_group] unless options[:availability_zone_group].blank?
214
+ request_hash['LaunchSpecification.KeyName'] = options[:key_name] unless options[:key_name].blank?
215
+ request_hash['LaunchSpecification.AddressingType'] = options[:addressing_type] unless options[:addressing_type].blank?
216
+ request_hash['LaunchSpecification.KernelId'] = options[:kernel_id] unless options[:kernel_id].blank?
217
+ request_hash['LaunchSpecification.RamdiskId'] = options[:ramdisk_id] unless options[:ramdisk_id].blank?
218
+ request_hash['LaunchSpecification.SubnetId'] = options[:subnet_id] unless options[:subnet_id].blank?
219
+ request_hash['LaunchSpecification.Placement.AvailabilityZone'] = options[:availability_zone] unless options[:availability_zone].blank?
220
+ request_hash['LaunchSpecification.Monitoring.Enabled'] = options[:monitoring_enabled] unless options[:monitoring_enabled].blank?
221
+ request_hash.merge!(amazonize_list('LaunchSpecification.SecurityGroup', options[:groups])) unless options[:groups].blank?
222
+ request_hash.merge!(amazonize_block_device_mappings(options[:block_device_mappings], 'LaunchSpecification.BlockDeviceMapping'))
223
+ unless options[:user_data].blank?
224
+ # See RightAws::Ec2#run_instances
225
+ options[:user_data].strip!
226
+ request_hash['LaunchSpecification.UserData'] = Base64.encode64(options[:user_data]).delete("\n") unless options[:user_data].blank?
227
+ end
228
+ link = generate_request("RequestSpotInstances", request_hash)
229
+ request_info(link, QEc2DescribeSpotInstanceParser.new(:logger => @logger))
230
+ end
231
+
232
+ # Cancel one or more Spot Instance requests.
233
+ #
234
+ # ec2.cancel_spot_instance_requests('sir-60662c03',"sir-d3c96e04", "sir-4fa8d804","sir-6992ce04") #=>
235
+ # [{:state=>"cancelled", :spot_instance_request_id=>"sir-60662c03"},
236
+ # {:state=>"cancelled", :spot_instance_request_id=>"sir-6992ce04"},
237
+ # {:state=>"cancelled", :spot_instance_request_id=>"sir-4fa8d804"},
238
+ # {:state=>"cancelled", :spot_instance_request_id=>"sir-d3c96e04"}]
239
+ #
240
+ def cancel_spot_instance_requests(*spot_instance_request_ids)
241
+ link = generate_request("CancelSpotInstanceRequests", amazonize_list('SpotInstanceRequestId', spot_instance_request_ids.flatten))
242
+ request_info(link, QEc2CancelSpotInstanceParser.new(:logger => @logger))
243
+ end
244
+
245
+ # Create the data feed for Spot Instances
246
+ # (Enables to view Spot Instance usage logs)
247
+ #
248
+ # ec2.create_spot_datafeed_subscription('bucket-for-konstantin-eu', 'splogs/') #=>
249
+ # { :owner_id=>"826693181925",
250
+ # :bucket=>"bucket-for-konstantin-eu",
251
+ # :prefix=>"splogs/",
252
+ # :state=>"Active"}
253
+ #
254
+ def create_spot_datafeed_subscription(bucket, prefix=nil)
255
+ request_hash = { 'Bucket' => bucket }
256
+ request_hash['Prefix'] = prefix unless prefix.blank?
257
+ link = generate_request("CreateSpotDatafeedSubscription", request_hash)
258
+ request_info(link, QEc2DescribeSpotDatafeedSubscriptionParser.new(:logger => @logger))
259
+ end
260
+
261
+ # Describe the data feed for Spot Instances.
262
+ #
263
+ # ec2.describe_spot_datafeed_subscription #=>
264
+ # { :owner_id=>"826693181925",
265
+ # :bucket=>"bucket-for-konstantin-eu",
266
+ # :prefix=>"splogs/",
267
+ # :state=>"Active"}
268
+ #
269
+ def describe_spot_datafeed_subscription
270
+ link = generate_request("DescribeSpotDatafeedSubscription")
271
+ request_info(link, QEc2DescribeSpotDatafeedSubscriptionParser.new(:logger => @logger))
272
+ end
273
+
274
+ # Delete the data feed for Spot Instances.
275
+ #
276
+ # ec2.delete_spot_datafeed_subscription #=> true
277
+ #
278
+ def delete_spot_datafeed_subscription()
279
+ link = generate_request("DeleteSpotDatafeedSubscription")
280
+ request_info(link, RightBoolResponseParser.new(:logger => @logger))
281
+ end
282
+
283
+ #-----------------------------------------------------------------
284
+ # PARSERS: Spot Instances
285
+ #-----------------------------------------------------------------
286
+
287
+ class QEc2DescribeSpotPriceHistoryParser < RightAWSParser #:nodoc:
288
+ def tagstart(name, attributes)
289
+ @item = {} if name == 'item'
290
+ end
291
+ def tagend(name)
292
+ case name
293
+ when 'instanceType' then @item[:instance_type] = @text
294
+ when 'productDescription' then @item[:product_description] = @text
295
+ when 'spotPrice' then @item[:spot_price] = @text.to_f
296
+ when 'timestamp' then @item[:timestamp] = @text
297
+ when 'item' then @result << @item
298
+ end
299
+ end
300
+ def reset
301
+ @result = []
302
+ end
303
+ end
304
+
305
+ class QEc2DescribeSpotInstanceParser < RightAWSParser #:nodoc:
306
+ def tagstart(name, attributes)
307
+ case full_tag_name
308
+ when %r{spotInstanceRequestSet/item$}
309
+ @item = {}
310
+ when %r{/blockDeviceMapping/item$}
311
+ @item[:block_device_mappings] ||= []
312
+ @block_device_mapping = {}
313
+ end
314
+ end
315
+ def tagend(name)
316
+ case name
317
+ when 'spotInstanceRequestId' then @item[:spot_instance_request_id]= @text
318
+ when 'spotPrice' then @item[:spot_price] = @text.to_f
319
+ when 'type' then @item[:type] = @text
320
+ when 'state' then @item[:state] = @text
321
+ when 'code' then @item[:fault_code] = @text
322
+ when 'message' then @item[:fault_message] = @text
323
+ when 'validFrom' then @item[:valid_from] = @text
324
+ when 'validUntil' then @item[:valid_until] = @text
325
+ when 'launchGroup' then @item[:launch_group] = @text
326
+ when 'availabilityZoneGroup' then @item[:availability_zone_group] = @text
327
+ when 'imageId' then @item[:image_id] = @text
328
+ when 'keyName' then @item[:key_name] = @text
329
+ when 'userData' then @item[:userData] = @text
330
+ when 'data' then @item[:data] = @text
331
+ when 'addressingType' then @item[:addressing_type] = @text
332
+ when 'instanceType' then @item[:instance_type] = @text
333
+ when 'availabilityZone' then @item[:availability_zone] = @text
334
+ when 'kernelId' then @item[:kernel_id] = @text
335
+ when 'ramdiskId' then @item[:ramdisk_id] = @text
336
+ when 'subnetId' then @item[:subnet_id] = @text
337
+ when 'instanceId' then @item[:instance_id] = @text
338
+ when 'createTime' then @item[:create_time] = @text
339
+ when 'productDescription' then @item[:product_description] = @text
340
+ when 'groupId' then (@item[:groups] ||= []) << @text
341
+ else
342
+ case full_tag_name
343
+ when %r{monitoring/enabled$}
344
+ @item[:monitoring_enabled] = @text == 'true'
345
+ when %r{/blockDeviceMapping/item} # no trailing $
346
+ case name
347
+ when 'deviceName' then @block_device_mapping[:device_name] = @text
348
+ when 'virtualName' then @block_device_mapping[:virtual_name] = @text
349
+ when 'volumeSize' then @block_device_mapping[:ebs_volume_size] = @text.to_i
350
+ when 'snapshotId' then @block_device_mapping[:ebs_snapshot_id] = @text
351
+ when 'deleteOnTermination' then @block_device_mapping[:ebs_delete_on_termination] = @text == 'true' ? true : false
352
+ when 'item' then @item[:block_device_mappings] << @block_device_mapping
353
+ end
354
+ when %r{spotInstanceRequestSet/item$}
355
+ @result << @item
356
+ end
357
+ end
358
+ end
359
+ def reset
360
+ @result = []
361
+ end
362
+ end
363
+
364
+ class QEc2CancelSpotInstanceParser < RightAWSParser #:nodoc:
365
+ def tagstart(name, attributes)
366
+ @item = {} if name == 'item'
367
+ end
368
+ def tagend(name)
369
+ case name
370
+ when 'spotInstanceRequestId' then @item[:spot_instance_request_id] = @text
371
+ when 'state' then @item[:state] = @text
372
+ when 'item' then @result << @item
373
+ end
374
+ end
375
+ def reset
376
+ @result = []
377
+ end
378
+ end
379
+
380
+ class QEc2DescribeSpotDatafeedSubscriptionParser < RightAWSParser #:nodoc:
381
+ def tagend(name)
382
+ case name
383
+ when 'ownerId' then @result[:owner_id] = @text
384
+ when 'bucket' then @result[:bucket] = @text
385
+ when 'prefix' then @result[:prefix] = @text
386
+ when 'state' then @result[:state] = @text
387
+ when 'fault' then @result[:fault] = @text
388
+ when 'code' then @result[:code] = @text
389
+ when 'message' then @result[:message] = @text
390
+ end
391
+ end
392
+ def reset
393
+ @result = {}
394
+ end
395
+ end
396
+
397
+ end
398
+
399
+ end
@@ -0,0 +1,571 @@
1
+ #
2
+ # Copyright (c) 2009 RightScale Inc
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ #
23
+
24
+ module RightAws
25
+
26
+ class Ec2
27
+
28
+ private
29
+
30
+ def vpc__split_list_and_filters(*params) # :nodoc:
31
+ params = params.flatten
32
+ filters = params.last.is_a?(Hash) ? params.pop : {}
33
+ # Make values to be arrays.
34
+ filters.each{|key, values| filters[key] = Array(values) }
35
+ [params, filters]
36
+ end
37
+
38
+ public
39
+
40
+ #-----------------
41
+ # VPC
42
+ #-----------------
43
+
44
+ # Describe VPCs
45
+ #
46
+ # ec2.describe_vpcs #=>
47
+ # [{:vpc_id=>"vpc-890ce2e0",
48
+ # :dhcp_options_id=>"default",
49
+ # :cidr_block=>"10.0.0.0/23",
50
+ # :state=>"available"}]
51
+ #
52
+ # ec2.describe_vpcs("vpc-890ce2e0")
53
+ #
54
+ def describe_vpcs(*list_and_filters)
55
+ list, filters = vpc__split_list_and_filters(list_and_filters)
56
+ cache_for = (list.empty? && filters.empty?) ? :describe_vpcs : nil
57
+ request_hash = {}
58
+ request_hash.merge!(amazonize_list('VpcId', list))
59
+ request_hash.merge!(amazonize_list(['Filter.?.Key','Filter.?.Value.?'], filters))
60
+ link = generate_request("DescribeVpcs", request_hash)
61
+ request_cache_or_info cache_for, link, QEc2DescribeVpcsParser, @@bench, cache_for
62
+ rescue Exception
63
+ on_exception
64
+ end
65
+
66
+ # Create VPC.
67
+ #
68
+ # ec2.create_vpc('10.0.0.0/23') #=>
69
+ # {:vpc_id=>"vpc-890ce2e0",
70
+ # :dhcp_options_id=>"default",
71
+ # :cidr_block=>"10.0.0.0/23",
72
+ # :state=>"pending"}
73
+ #
74
+ def create_vpc(cidr_block)
75
+ link = generate_request("CreateVpc",'CidrBlock' => cidr_block )
76
+ request_info(link, QEc2DescribeVpcsParser.new(:logger => @logger)).first
77
+ rescue Exception
78
+ on_exception
79
+ end
80
+
81
+ # Delete VPC.
82
+ #
83
+ # ec2.delete_vpc("vpc-890ce2e0") #=> true
84
+ #
85
+ def delete_vpc(vpc_id)
86
+ link = generate_request("DeleteVpc", 'VpcId' => vpc_id )
87
+ request_info(link, RightHttp2xxParser.new(:logger => @logger))
88
+ rescue Exception
89
+ on_exception
90
+ end
91
+
92
+ #-----------------
93
+ # Subnets
94
+ #-----------------
95
+
96
+ # Describe Subnet.
97
+ #
98
+ # ec2.describe_subnets #=>
99
+ # [{:available_ip_address_count=>"251",
100
+ # :vpc_id=>"vpc-890ce2e0",
101
+ # :availability_zone=>"us-east-1a",
102
+ # :subnet_id=>"subnet-770de31e",
103
+ # :cidr_block=>"10.0.1.0/24",
104
+ # :state=>"available"}]
105
+ #
106
+ def describe_subnets(*list_and_filters)
107
+ list, filters = vpc__split_list_and_filters(list_and_filters)
108
+ cache_for = (list.empty? && filters.empty?) ? :describe_subnets : nil
109
+ request_hash = {}
110
+ request_hash.merge!(amazonize_list('SubnetId', list))
111
+ request_hash.merge!(amazonize_list(['Filter.?.Key','Filter.?.Value.?'], filters))
112
+ link = generate_request("DescribeSubnets", request_hash)
113
+ request_cache_or_info cache_for, link, QEc2DescribeSubnetsParser, @@bench, cache_for
114
+ rescue Exception
115
+ on_exception
116
+ end
117
+
118
+ # Create Subnet.
119
+ #
120
+ # ec2.create_subnet("vpc-890ce2e0",'10.0.1.0/24') #=>
121
+ # {:available_ip_address_count=>"251",
122
+ # :vpc_id=>"vpc-890ce2e0",
123
+ # :availability_zone=>"us-east-1a",
124
+ # :subnet_id=>"subnet-770de31e",
125
+ # :cidr_block=>"10.0.1.0/24",
126
+ # :state=>"pending"}
127
+ #
128
+ def create_subnet(vpc_id, cidr_block, availability_zone = nil)
129
+ request_hash = { 'VpcId' => vpc_id,
130
+ 'CidrBlock' => cidr_block }
131
+ request_hash['AvailabilityZone'] = availability_zone unless availability_zone.blank?
132
+ link = generate_request("CreateSubnet", request_hash)
133
+ request_info(link, QEc2DescribeSubnetsParser.new(:logger => @logger)).first
134
+ rescue Exception
135
+ on_exception
136
+ end
137
+
138
+ # Delete Subnet.
139
+ #
140
+ # ec2.delete_subnet("subnet-770de31e") #=> true
141
+ #
142
+ def delete_subnet(subnet_id)
143
+ link = generate_request("DeleteSubnet", 'SubnetId' => subnet_id )
144
+ request_info(link, RightHttp2xxParser.new(:logger => @logger))
145
+ rescue Exception
146
+ on_exception
147
+ end
148
+
149
+ #-----------------
150
+ # DHCP Options
151
+ #-----------------
152
+
153
+ # Describe DHCP options.
154
+ #
155
+ # ec2.describe_dhcp_options #=>
156
+ # [{:dhcp_options_id=>"dopt-cb0de3a2",
157
+ # :dhcp_configuration_set=>
158
+ # {"netbios-node-type"=>["1"], "domain-name"=>["my.awesomesite.ru"]}}]
159
+ #
160
+ def describe_dhcp_options(*list)
161
+ list = list.flatten
162
+ cache_for = list.empty? ? :describe_dhcp_options : nil
163
+ request_hash = amazonize_list('DhcpOptionsId', list)
164
+ link = generate_request("DescribeDhcpOptions", request_hash)
165
+ request_cache_or_info cache_for, link, QEc2DescribeDhcpOptionsParser, @@bench, cache_for
166
+ rescue Exception
167
+ on_exception
168
+ end
169
+
170
+ # Create DHCP options.
171
+ #
172
+ # ec2.create_dhcp_options('domain-name' => 'my.awesomesite.ru',
173
+ # 'netbios-node-type' => 1) #=>
174
+ # {:dhcp_options_id=>"dopt-cb0de3a2",
175
+ # :dhcp_configuration_set=>
176
+ # {"netbios-node-type"=>["1"], "domain-name"=>["my.awesomesite.ru"]}}
177
+ #
178
+ def create_dhcp_options(dhcp_configuration)
179
+ dhcp_configuration.each{ |key, values| dhcp_configuration[key] = Array(values) }
180
+ request_hash = amazonize_list(['DhcpConfiguration.?.Key','DhcpConfiguration.?.Value.?'], dhcp_configuration)
181
+ link = generate_request("CreateDhcpOptions", request_hash)
182
+ request_info(link, QEc2DescribeDhcpOptionsParser.new(:logger => @logger)).first
183
+ rescue Exception
184
+ on_exception
185
+ end
186
+
187
+ # Associate DHCP options
188
+ #
189
+ # ec2.associate_dhcp_options("dopt-cb0de3a2", "vpc-890ce2e0" ) #=> true
190
+ # ec2.describe_vpcs #=>
191
+ # [{:vpc_id=>"vpc-890ce2e0",
192
+ # :dhcp_options_id=>"dopt-cb0de3a2",
193
+ # :cidr_block=>"10.0.0.0/23",
194
+ # :state=>"available"}]
195
+ #
196
+ def associate_dhcp_options(dhcp_options_id, vpc_id)
197
+ link = generate_request("AssociateDhcpOptions", 'DhcpOptionsId' => dhcp_options_id,
198
+ 'VpcId' => vpc_id)
199
+ request_info(link, RightHttp2xxParser.new(:logger => @logger))
200
+ rescue Exception
201
+ on_exception
202
+ end
203
+
204
+ # Delete DHCP Options.
205
+ #
206
+ # ec2.delete_dhcp_options("dopt-cb0de3a2") #=> true
207
+ #
208
+ def delete_dhcp_options(dhcp_options_id)
209
+ link = generate_request("DeleteDhcpOptions", 'DhcpOptionsId' => dhcp_options_id )
210
+ request_info(link, RightHttp2xxParser.new(:logger => @logger))
211
+ rescue Exception
212
+ on_exception
213
+ end
214
+
215
+ #-----------------
216
+ # Customer Gateways
217
+ #-----------------
218
+
219
+ # Describe customer gateways.
220
+ #
221
+ # ec2.describe_customer_gateways
222
+ #
223
+ # [{:type=>"ipsec.1",
224
+ # :ip_address=>"12.1.2.3",
225
+ # :bgp_asn=>"65534",
226
+ # :state=>"available",
227
+ # :customer_gateway_id=>"cgw-d5a643bc"}]
228
+ #
229
+ def describe_customer_gateways(*list_and_filters)
230
+ list, filters = vpc__split_list_and_filters(list_and_filters)
231
+ cache_for = (list.empty? && filters.empty?) ? :describe_customer_gateways : nil
232
+ request_hash = {}
233
+ request_hash.merge!(amazonize_list('CustomerGatewayId', list))
234
+ request_hash.merge!(amazonize_list(['Filter.?.Key','Filter.?.Value.?'], filters))
235
+ link = generate_request("DescribeCustomerGateways", request_hash)
236
+ request_cache_or_info cache_for, link, QEc2DescribeCustomerGatewaysParser, @@bench, cache_for
237
+ rescue Exception
238
+ on_exception
239
+ end
240
+
241
+ # Create customer gateway.
242
+ #
243
+ # ec2.create_customer_gateway('ipsec.1', '12.1.2.3', 65534) #=>
244
+ # {:type=>"ipsec.1",
245
+ # :bgp_asn=>"65534",
246
+ # :ip_address=>"12.1.2.3",
247
+ # :state=>"pending",
248
+ # :customer_gateway_id=>"cgw-d5a643bc"}
249
+ #
250
+ def create_customer_gateway(type, ip_address, bgp_asn)
251
+ link = generate_request("CreateCustomerGateway", 'Type' => type,
252
+ 'IpAddress' => ip_address,
253
+ 'BgpAsn' => bgp_asn )
254
+ request_info(link, QEc2DescribeCustomerGatewaysParser.new(:logger => @logger)).first
255
+ rescue Exception
256
+ on_exception
257
+ end
258
+
259
+ # Delete customer gateway.
260
+ #
261
+ # ec2.delete_customer_gateway("cgw-d5a643bc") #=> true
262
+ #
263
+ def delete_customer_gateway(customer_gateway_id)
264
+ link = generate_request("DeleteCustomerGateway", 'CustomerGatewayId' => customer_gateway_id )
265
+ request_info(link, RightHttp2xxParser.new(:logger => @logger))
266
+ rescue Exception
267
+ on_exception
268
+ end
269
+
270
+ #-----------------
271
+ # VPN Gateways
272
+ #-----------------
273
+
274
+ # Describe VPN gateways.
275
+ #
276
+ # ec2.describe_vpn_gateways #=>
277
+ # [{:type=>"ipsec.1",
278
+ # :availability_zone=>"us-east-1a",
279
+ # :attachments=>[{:vpc_id=>"vpc-890ce2e0", :state=>"attached"}],
280
+ # :vpn_gateway_id=>"vgw-dfa144b6"}]
281
+ #
282
+ def describe_vpn_gateways(*list_and_filters)
283
+ list, filters = vpc__split_list_and_filters(list_and_filters)
284
+ cache_for = (list.empty? && filters.empty?) ? :describe_vpn_gateways : nil
285
+ request_hash = {}
286
+ request_hash.merge!(amazonize_list('VpnGatewayId', list))
287
+ request_hash.merge!(amazonize_list(['Filter.?.Key','Filter.?.Value.?'], filters))
288
+ link = generate_request("DescribeVpnGateways", request_hash)
289
+ request_cache_or_info cache_for, link, QEc2DescribeVpnGatewaysParser, @@bench, cache_for
290
+ rescue Exception
291
+ on_exception
292
+ end
293
+
294
+ # Create VPN gateway.
295
+ #
296
+ # ec2.create_vpn_gateway('ipsec.1') #=>
297
+ # {:type=>"ipsec.1",
298
+ # :availability_zone=>"us-east-1a",
299
+ # :attachments=>[nil],
300
+ # :vpn_gateway_id=>"vgw-dfa144b6"}
301
+ #
302
+ def create_vpn_gateway(type, availability_zone=nil)
303
+ request_hash = { 'Type' => type }
304
+ request_hash['AvailabilityZone'] = availability_zone unless availability_zone.blank?
305
+ link = generate_request("CreateVpnGateway", request_hash )
306
+ request_info(link, QEc2DescribeVpnGatewaysParser.new(:logger => @logger)).first
307
+ rescue Exception
308
+ on_exception
309
+ end
310
+
311
+ # Attach VPN gateway.
312
+ #
313
+ # ec2.attach_vpn_gateway('vgw-dfa144b6','vpc-890ce2e0') #=>
314
+ # {:vpc_id=>"vpc-890ce2e0", :state=>"attaching"}
315
+ #
316
+ def attach_vpn_gateway(vpn_gateway_id, vpc_id)
317
+ link = generate_request("AttachVpnGateway", 'VpnGatewayId' => vpn_gateway_id,
318
+ 'VpcId' => vpc_id )
319
+ request_info(link, QEc2AttachVpnGatewayParser.new(:logger => @logger))
320
+ rescue Exception
321
+ on_exception
322
+ end
323
+
324
+ # Detach VPN gateway.
325
+ #
326
+ # ec2.detach_vpn_gateway('vgw-dfa144b6','vpc-890ce2e0') #=> true
327
+ #
328
+ def detach_vpn_gateway(vpn_gateway_id, vpc_id)
329
+ link = generate_request("DetachVpnGateway", 'VpnGatewayId' => vpn_gateway_id,
330
+ 'VpcId' => vpc_id )
331
+ request_info(link, RightHttp2xxParser.new(:logger => @logger))
332
+ rescue Exception
333
+ on_exception
334
+ end
335
+
336
+ # Delete vpn gateway.
337
+ #
338
+ # ec2.delete_vpn_gateway("vgw-dfa144b6") #=> true
339
+ #
340
+ def delete_vpn_gateway(vpn_gateway_id)
341
+ link = generate_request("DeleteVpnGateway", 'VpnGatewayId' => vpn_gateway_id )
342
+ request_info(link, RightHttp2xxParser.new(:logger => @logger))
343
+ rescue Exception
344
+ on_exception
345
+ end
346
+
347
+ #-----------------
348
+ # VPN Connections
349
+ #-----------------
350
+
351
+ # Describe VPN connections.
352
+ #
353
+ # ec2.describe_vpn_connections #=>
354
+ # [{:type=>"ipsec.1",
355
+ # :vpn_connection_id=>"vpn-a9a643c0",
356
+ # :customer_gateway_configuration=>
357
+ # "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<vpn_connection id=\"vpn-a9a643c0\">\n...</vpn_connection>\n",
358
+ # :state=>"available",
359
+ # :vpn_gateway_id=>"vgw-dfa144b6",
360
+ # :customer_gateway_id=>"cgw-81a643e8"}]
361
+ #
362
+ def describe_vpn_connections(*list_and_filters)
363
+ list, filters = vpc__split_list_and_filters(list_and_filters)
364
+ cache_for = (list.empty? && filters.empty?) ? :describe_vpn_connections : nil
365
+ request_hash = {}
366
+ request_hash.merge!(amazonize_list('VpnConnectionId', list))
367
+ request_hash.merge!(amazonize_list(['Filter.?.Key','Filter.?.Value.?'], filters))
368
+ link = generate_request("DescribeVpnConnections", request_hash)
369
+ request_cache_or_info cache_for, link, QEc2DescribeVpnConnectionsParser, @@bench, cache_for
370
+ rescue Exception
371
+ on_exception
372
+ end
373
+
374
+ # Create VPN connection.
375
+ #
376
+ # ec2.create_vpn_connection('ipsec.1', 'cgw-81a643e8' ,'vgw-dfa144b6')
377
+ # {:customer_gateway_id=>"cgw-81a643e8",
378
+ # :vpn_connection_id=>"vpn-a9a643c0",
379
+ # :customer_gateway_configuration=>
380
+ # "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<vpn_connection id=\"vpn-a9a643c0\">\n...</vpn_connection>\n",
381
+ # :state=>"pending",
382
+ # :vpn_gateway_id=>"vgw-dfa144b6"}
383
+ #
384
+ def create_vpn_connection(type, customer_gateway_id, vpn_gateway_id)
385
+ link = generate_request("CreateVpnConnection", 'Type' => type,
386
+ 'CustomerGatewayId' => customer_gateway_id,
387
+ 'VpnGatewayId' => vpn_gateway_id )
388
+ request_info(link, QEc2DescribeVpnConnectionsParser.new(:logger => @logger)).first
389
+ rescue Exception
390
+ on_exception
391
+ end
392
+
393
+ # Delete VPN connection.
394
+ #
395
+ # ec2.delete_vpn_connection("vpn-a9a643c0") #=> true
396
+ #
397
+ def delete_vpn_connection(vpn_connection_id)
398
+ link = generate_request("DeleteVpnConnection", 'VpnConnectionId' => vpn_connection_id )
399
+ request_info(link, RightHttp2xxParser.new(:logger => @logger))
400
+ rescue Exception
401
+ on_exception
402
+ end
403
+
404
+ #-----------------
405
+ # Parsers
406
+ #-----------------
407
+
408
+ class QEc2DescribeVpcsParser < RightAWSParser #:nodoc:
409
+ def tagstart(name, attributes)
410
+ case name
411
+ when 'item', 'vpc' then @item = {}
412
+ end
413
+ end
414
+ def tagend(name)
415
+ case name
416
+ when 'vpcId' then @item[:vpc_id] = @text
417
+ when 'state' then @item[:state] = @text
418
+ when 'dhcpOptionsId' then @item[:dhcp_options_id] = @text
419
+ when 'cidrBlock' then @item[:cidr_block] = @text
420
+ when 'item', 'vpc' then @result << @item
421
+ end
422
+ end
423
+ def reset
424
+ @result = []
425
+ end
426
+ end
427
+
428
+ class QEc2DescribeSubnetsParser < RightAWSParser #:nodoc:
429
+ def tagstart(name, attributes)
430
+ case name
431
+ when 'item', 'subnet' then @item = {}
432
+ end
433
+ end
434
+ def tagend(name)
435
+ case name
436
+ when 'subnetId' then @item[:subnet_id] = @text
437
+ when 'state' then @item[:state] = @text
438
+ when 'vpcId' then @item[:vpc_id] = @text
439
+ when 'cidrBlock' then @item[:cidr_block] = @text
440
+ when 'availabilityZone' then @item[:availability_zone] = @text
441
+ when 'availableIpAddressCount' then @item[:available_ip_address_count] = @text
442
+ when 'item', 'subnet' then @result << @item
443
+ end
444
+ end
445
+ def reset
446
+ @result = []
447
+ end
448
+ end
449
+
450
+ class QEc2DescribeDhcpOptionsParser < RightAWSParser #:nodoc:
451
+ def tagstart(name, attributes)
452
+ case full_tag_name
453
+ when @p1, @p2
454
+ @item = { :dhcp_configuration_set => {} }
455
+ end
456
+ end
457
+ def tagend(name)
458
+ case name
459
+ when 'dhcpOptionsId' then @item[:dhcp_options_id] = @text
460
+ when 'key' then @conf_item_key = @text
461
+ when 'value' then (@item[:dhcp_configuration_set][@conf_item_key] ||= []) << @text
462
+ end
463
+ case full_tag_name
464
+ when @p1, @p2
465
+ @result << @item
466
+ end
467
+ end
468
+ def reset
469
+ @p1 = 'DescribeDhcpOptionsResponse/dhcpOptionsSet/item'
470
+ @p2 = 'CreateDhcpOptionsResponse/dhcpOptions'
471
+ @result = []
472
+ end
473
+ end
474
+
475
+ class QEc2DescribeCustomerGatewaysParser < RightAWSParser #:nodoc:
476
+ def tagstart(name, attributes)
477
+ case name
478
+ when 'item', 'customerGateway'
479
+ @item = {}
480
+ end
481
+ end
482
+ def tagend(name)
483
+ case name
484
+ when 'customerGatewayId' then @item[:customer_gateway_id] = @text
485
+ when 'state' then @item[:state] = @text
486
+ when 'type' then @item[:type] = @text
487
+ when 'ipAddress' then @item[:ip_address] = @text
488
+ when 'bgpAsn' then @item[:bgp_asn] = @text
489
+ when 'item', 'customerGateway' then @result << @item
490
+ end
491
+ end
492
+ def reset
493
+ @result = []
494
+ end
495
+ end
496
+
497
+ class QEc2DescribeVpnGatewaysParser < RightAWSParser #:nodoc:
498
+ def tagstart(name, attributes)
499
+ case full_tag_name
500
+ when @p1, @p2
501
+ @item = { :attachments => [] }
502
+ when "#{@p1}/attachments/item",
503
+ "#{@p2}/attachments/item"
504
+ @attachment = {}
505
+ end
506
+ end
507
+ def tagend(name)
508
+ case name
509
+ when 'vpnGatewayId' then @item[:vpn_gateway_id] = @text
510
+ when 'availabilityZone' then @item[:availability_zone] = @text
511
+ when 'type' then @item[:type] = @text
512
+ when 'vpcId' then @attachment[:vpc_id] = @text
513
+ end
514
+ case full_tag_name
515
+ when "#{@p1}/state",
516
+ "#{@p2}/state"
517
+ @item[:state] = @text
518
+ when "#{@p1}/attachments/item/state",
519
+ "#{@p2}/attachments/item/state"
520
+ @attachment[:state] = @text
521
+ when "#{@p1}/attachments/item",
522
+ "#{@p2}/attachments/item"
523
+ @item[:attachments] << @attachment unless @attachment.blank?
524
+ when @p1, @p2
525
+ @result << @item
526
+ end
527
+ end
528
+ def reset
529
+ @p1 = 'DescribeVpnGatewaysResponse/vpnGatewaySet/item'
530
+ @p2 = 'CreateVpnGatewayResponse/vpnGateway'
531
+ @result = []
532
+ end
533
+ end
534
+
535
+ class QEc2AttachVpnGatewayParser < RightAWSParser #:nodoc:
536
+ def tagend(name)
537
+ case name
538
+ when 'vpcId' then @result[:vpc_id] = @text
539
+ when 'state' then @result[:state] = @text
540
+ end
541
+ end
542
+ def reset
543
+ @result = {}
544
+ end
545
+ end
546
+
547
+
548
+ class QEc2DescribeVpnConnectionsParser < RightAWSParser #:nodoc:
549
+ def tagstart(name, attributes)
550
+ case name
551
+ when 'item', 'vpnConnection' then @item = {}
552
+ end
553
+ end
554
+ def tagend(name)
555
+ case name
556
+ when 'vpnConnectionId' then @item[:vpn_connection_id] = @text
557
+ when 'state' then @item[:state] = @text
558
+ when 'type' then @item[:type] = @text
559
+ when 'vpnGatewayId' then @item[:vpn_gateway_id] = @text
560
+ when 'customerGatewayId' then @item[:customer_gateway_id] = @text
561
+ when 'customerGatewayConfiguration' then @item[:customer_gateway_configuration] = @text
562
+ when 'item','vpnConnection' then @result << @item
563
+ end
564
+ end
565
+ def reset
566
+ @result = []
567
+ end
568
+ end
569
+
570
+ end
571
+ end