right_aws 1.9.0 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. data/History.txt +164 -13
  2. data/Manifest.txt +28 -1
  3. data/README.txt +12 -10
  4. data/Rakefile +56 -29
  5. data/lib/acf/right_acf_interface.rb +343 -172
  6. data/lib/acf/right_acf_invalidations.rb +144 -0
  7. data/lib/acf/right_acf_origin_access_identities.rb +230 -0
  8. data/lib/acf/right_acf_streaming_interface.rb +229 -0
  9. data/lib/acw/right_acw_interface.rb +248 -0
  10. data/lib/as/right_as_interface.rb +698 -0
  11. data/lib/awsbase/right_awsbase.rb +755 -115
  12. data/lib/awsbase/support.rb +2 -78
  13. data/lib/awsbase/version.rb +9 -0
  14. data/lib/ec2/right_ec2.rb +274 -1294
  15. data/lib/ec2/right_ec2_ebs.rb +514 -0
  16. data/lib/ec2/right_ec2_images.rb +444 -0
  17. data/lib/ec2/right_ec2_instances.rb +797 -0
  18. data/lib/ec2/right_ec2_monitoring.rb +70 -0
  19. data/lib/ec2/right_ec2_placement_groups.rb +108 -0
  20. data/lib/ec2/right_ec2_reserved_instances.rb +243 -0
  21. data/lib/ec2/right_ec2_security_groups.rb +496 -0
  22. data/lib/ec2/right_ec2_spot_instances.rb +422 -0
  23. data/lib/ec2/right_ec2_tags.rb +139 -0
  24. data/lib/ec2/right_ec2_vpc.rb +598 -0
  25. data/lib/ec2/right_ec2_vpc2.rb +382 -0
  26. data/lib/ec2/right_ec2_windows_mobility.rb +84 -0
  27. data/lib/elb/right_elb_interface.rb +573 -0
  28. data/lib/emr/right_emr_interface.rb +728 -0
  29. data/lib/iam/right_iam_access_keys.rb +71 -0
  30. data/lib/iam/right_iam_groups.rb +195 -0
  31. data/lib/iam/right_iam_interface.rb +341 -0
  32. data/lib/iam/right_iam_mfa_devices.rb +67 -0
  33. data/lib/iam/right_iam_users.rb +251 -0
  34. data/lib/rds/right_rds_interface.rb +1657 -0
  35. data/lib/right_aws.rb +30 -13
  36. data/lib/route_53/right_route_53_interface.rb +641 -0
  37. data/lib/s3/right_s3.rb +108 -41
  38. data/lib/s3/right_s3_interface.rb +349 -118
  39. data/lib/sdb/active_sdb.rb +388 -54
  40. data/lib/sdb/right_sdb_interface.rb +323 -64
  41. data/lib/sns/right_sns_interface.rb +286 -0
  42. data/lib/sqs/right_sqs.rb +1 -2
  43. data/lib/sqs/right_sqs_gen2.rb +73 -17
  44. data/lib/sqs/right_sqs_gen2_interface.rb +146 -73
  45. data/lib/sqs/right_sqs_interface.rb +12 -22
  46. data/right_aws.gemspec +91 -0
  47. data/test/README.mdown +39 -0
  48. data/test/acf/test_right_acf.rb +11 -19
  49. data/test/awsbase/test_helper.rb +2 -0
  50. data/test/awsbase/test_right_awsbase.rb +11 -0
  51. data/test/ec2/test_right_ec2.rb +32 -1
  52. data/test/elb/test_helper.rb +2 -0
  53. data/test/elb/test_right_elb.rb +43 -0
  54. data/test/rds/test_helper.rb +2 -0
  55. data/test/rds/test_right_rds.rb +120 -0
  56. data/test/route_53/fixtures/a_record.xml +18 -0
  57. data/test/route_53/fixtures/alias_record.xml +18 -0
  58. data/test/route_53/test_helper.rb +2 -0
  59. data/test/route_53/test_right_route_53.rb +141 -0
  60. data/test/s3/test_right_s3.rb +176 -42
  61. data/test/s3/test_right_s3_stubbed.rb +6 -4
  62. data/test/sdb/test_active_sdb.rb +120 -19
  63. data/test/sdb/test_batch_put_attributes.rb +54 -0
  64. data/test/sdb/test_right_sdb.rb +71 -16
  65. data/test/sns/test_helper.rb +2 -0
  66. data/test/sns/test_right_sns.rb +153 -0
  67. data/test/sqs/test_right_sqs.rb +0 -6
  68. data/test/sqs/test_right_sqs_gen2.rb +104 -49
  69. data/test/ts_right_aws.rb +1 -0
  70. metadata +181 -22
@@ -0,0 +1,70 @@
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
+ # Enables monitoring for a running instances. For more information, refer to the Amazon CloudWatch Developer Guide.
29
+ #
30
+ # ec2.monitor_instances('i-8437ddec') #=>
31
+ # {:instance_id=>"i-8437ddec", :monitoring_state=>"pending"}
32
+ #
33
+ def monitor_instances(*list)
34
+ link = generate_request("MonitorInstances", amazonize_list('InstanceId', list.flatten) )
35
+ request_info(link, QEc2MonitorInstancesParser.new(:logger => @logger)).first
36
+ rescue Exception
37
+ on_exception
38
+ end
39
+
40
+ # Disables monitoring for a running instances. For more information, refer to the Amazon CloudWatch Developer Guide.
41
+ #
42
+ # ec2.unmonitor_instances('i-8437ddec') #=>
43
+ # {:instance_id=>"i-8437ddec", :monitoring_state=>"disabling"}
44
+ #
45
+ def unmonitor_instances(*list)
46
+ link = generate_request("UnmonitorInstances", amazonize_list('InstanceId', list.flatten) )
47
+ request_info(link, QEc2MonitorInstancesParser.new(:logger => @logger)).first
48
+ rescue Exception
49
+ on_exception
50
+ end
51
+
52
+ class QEc2MonitorInstancesParser < RightAWSParser #:nodoc:
53
+ def tagstart(name, attributes)
54
+ @item = {} if name == 'item'
55
+ end
56
+ def tagend(name)
57
+ case name
58
+ when 'instanceId' then @item[:instance_id] = @text
59
+ when 'state' then @item[:monitoring_state] = @text
60
+ when 'item' then @result << @item
61
+ end
62
+ end
63
+ def reset
64
+ @result = []
65
+ end
66
+ end
67
+
68
+ end
69
+
70
+ end
@@ -0,0 +1,108 @@
1
+ #
2
+ # Copyright (c) 2010 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
+ # Placement Groups
30
+ #-----------------------------------------------------------------
31
+
32
+ # Describe placement groups.
33
+ #
34
+ # Accepts a list of placement groups and/or a set of filters as the last parameter.
35
+ #
36
+ # Filters: group-name, state, strategy
37
+ #
38
+ # If you don’t specify a particular placement group, the response includes
39
+ # information about all of them. The information includes the group name, the strategy,
40
+ # and the group state (e.g., pending, available, etc.).
41
+ #
42
+ # ec2.describe_placement_groups #=>
43
+ # [{:state=>"available", :strategy=>"cluster", :group_name=>"kd_first"},
44
+ # {:state=>"available", :strategy=>"cluster", :group_name=>"kd_second"}]
45
+ #
46
+ # ec2.describe_placement_groups('kd_second') #=>
47
+ # [{:strategy=>"cluster", :group_name=>"kd_second", :state=>"available"}]
48
+ #
49
+ # P.S. filters: http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference_query_DescribePlacementGroups.html
50
+ #
51
+ def describe_placement_groups(*list_and_options)
52
+ describe_resources_with_list_and_options('DescribePlacementGroups', 'GroupName', QEc2DescribePlacementGroupsParser, list_and_options)
53
+ end
54
+
55
+ # Create placement group creates a placement group (i.e. logical cluster group)
56
+ # into which you can then launch instances. You must provide a name for the group
57
+ # that is unique within the scope of your account. You must also provide a strategy
58
+ # value. Currently the only value accepted is cluster.
59
+ #
60
+ # ec2.create_placement_group('kd_second') #=> true
61
+ #
62
+ def create_placement_group(placement_group_name, strategy = 'cluster')
63
+ link = generate_request('CreatePlacementGroup',
64
+ 'GroupName' => placement_group_name.to_s,
65
+ 'Strategy' => strategy.to_s)
66
+ request_info(link, RightBoolResponseParser.new(:logger => @logger))
67
+ rescue Exception
68
+ on_exception
69
+ end
70
+
71
+ # Delete placement group deletes a placement group that you own. The group must not
72
+ # contain any instances.
73
+ #
74
+ # ec2.delete_placement_group('kd_second') #=> true
75
+ #
76
+ def delete_placement_group(placement_group_name)
77
+ link = generate_request('DeletePlacementGroup',
78
+ 'GroupName' => placement_group_name.to_s)
79
+ request_info(link, RightBoolResponseParser.new(:logger => @logger))
80
+ rescue Exception
81
+ on_exception
82
+ end
83
+
84
+ #-----------------------------------------------------------------
85
+ # PARSERS: Placement Groups
86
+ #-----------------------------------------------------------------
87
+
88
+ class QEc2DescribePlacementGroupsParser < RightAWSParser #:nodoc:
89
+ def tagstart(name, attributes)
90
+ case name
91
+ when 'item' then @item = {}
92
+ end
93
+ end
94
+ def tagend(name)
95
+ case name
96
+ when 'groupName' then @item[:group_name] = @text
97
+ when 'strategy' then @item[:strategy] = @text
98
+ when 'state' then @item[:state] = @text
99
+ when 'item' then @result << @item
100
+ end
101
+ end
102
+ def reset
103
+ @result = []
104
+ end
105
+ end
106
+
107
+ end
108
+ end
@@ -0,0 +1,243 @@
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
+ RESERVED_INSTANCE_API_VERSION = (API_VERSION > '2012-10-01') ? API_VERSION : '2012-10-01'
29
+
30
+ #-----------------------------------------------------------------
31
+ # Reserved instances
32
+ #-----------------------------------------------------------------
33
+
34
+ # Retrieve reserved instances list.
35
+ #
36
+ # Accepts a list of reserved instances and/or a set of filters as the last parameter.
37
+ #
38
+ # Filters: availability-zone, duration, fixed-price, instance-type, product-description,
39
+ # reserved-instances-id, start, state, tag-key, tag-value, tag:key, usage-price
40
+ #
41
+ # ec2.describe_reserved_instances #=>
42
+ # [{:tags=>{},
43
+ # :aws_id=>"4357912c-0000-0000-0000-15ca71a8e66d",
44
+ # :aws_instance_type=>"m1.small",
45
+ # :aws_availability_zone=>"us-east-1c",
46
+ # :aws_start=>"2010-03-18T20:39:39.569Z",
47
+ # :aws_duration=>94608000,
48
+ # :aws_fixed_price=>350.0,
49
+ # :aws_usage_price=>0.03,
50
+ # :aws_instance_count=>1,
51
+ # :aws_product_description=>"Linux/UNIX",
52
+ # :aws_state=>"active",
53
+ # :instance_tenancy=>"default",
54
+ # :currency_code=>"USD",
55
+ # :offering_type=>"Medium Utilization"}]
56
+ #
57
+ # ec2.describe_reserved_instances(:filters => {'availability-zone' => 'us-east-1a'})
58
+ #
59
+ # P.S. filters: http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/index.html?ApiReference-query-DescribeReservedInstances.html
60
+ #
61
+ def describe_reserved_instances(*list_and_options)
62
+ list_and_options = merge_new_options_into_list_and_options(list_and_options, :options => {:api_version => RESERVED_INSTANCE_API_VERSION})
63
+ describe_resources_with_list_and_options('DescribeReservedInstances', 'ReservedInstancesId', QEc2DescribeReservedInstancesParser, list_and_options)
64
+ end
65
+
66
+ # Retrieve reserved instances offerings.
67
+ #
68
+ # Accepts a list of reserved instances offerings and/or a set of filters as the last parameter.
69
+ #
70
+ # Filters: availability-zone, duration, fixed-price, instance-type, product-description, reserved-instances-offering-id, usage-price
71
+ #
72
+ # ec2.describe_reserved_instances_offerings #=>
73
+ # [{:recurring_charges=>[{:frequency=>"Hourly", :amount=>"0.095"}],
74
+ # :pricing_details_set=>[],
75
+ # :aws_id=>"438012d3-4031-43ff-9241-2964d1bf71d8",
76
+ # :aws_instance_type=>"c1.medium",
77
+ # :aws_availability_zone=>"us-east-1e",
78
+ # :aws_duration=>94608000,
79
+ # :aws_fixed_price=>775.0,
80
+ # :aws_usage_price=>0.0,
81
+ # :aws_product_description=>"Red Hat Enterprise Linux",
82
+ # :instance_tenancy=>"default",
83
+ # :currency_code=>"USD",
84
+ # :offering_type=>"Heavy Utilization",
85
+ # :marketplace=>false},
86
+ # { :recurring_charges=>[{:frequency=>"Hourly", :amount=>"0.095"}],
87
+ # :pricing_details_set=>[],
88
+ # :aws_id=>"649fd0c8-6cb4-47bf-83db-7a844016afa7",
89
+ # :aws_instance_type=>"c1.medium",
90
+ # :aws_availability_zone=>"us-east-1e",
91
+ # :aws_duration=>94608000,
92
+ # :aws_fixed_price=>775.0,
93
+ # :aws_usage_price=>0.0,
94
+ # :aws_product_description=>"Red Hat Enterprise Linux (Amazon VPC)",
95
+ # :instance_tenancy=>"default",
96
+ # :currency_code=>"USD",
97
+ # :offering_type=>"Heavy Utilization",
98
+ # :marketplace=>false}, ... ]
99
+ #
100
+ # ec2.describe_reserved_instances_offerings(:filters => {'availability-zone' => 'us-east-1c'})
101
+ #
102
+ # # Get all ReservedInstancesOfferings (list by 50 items)
103
+ # result = ec2.describe_reserved_instances_offerings(:max_results => 50) do |response|
104
+ # puts response[:items].count
105
+ # true
106
+ # end
107
+ #
108
+ # # Get first 400 ReservedInstancesOfferings.
109
+ # # P.S. it stops making calls one the block below returns false.
110
+ # max_count_to_get = 400
111
+ # counter = 0
112
+ # result = ec2.describe_reserved_instances_offerings do |response|
113
+ # counter += response[:items].count
114
+ # max_count_to_get <= counter
115
+ # end
116
+ #
117
+ # P.S. filters: http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/index.html?ApiReference-query-DescribeReservedInstancesOfferings.html
118
+ #
119
+ def describe_reserved_instances_offerings(*list_and_options, &block)
120
+ result = []
121
+ list_and_options = merge_new_options_into_list_and_options(list_and_options, :options => {:api_version => RESERVED_INSTANCE_API_VERSION})
122
+ incrementally_list_items('DescribeReservedInstancesOfferings', 'ReservedInstancesOfferingId', QEc2DescribeReservedInstancesOfferingsParser, list_and_options) do |response|
123
+ result += response[:items]
124
+ block ? block.call(response) : true
125
+ end
126
+ result
127
+ end
128
+
129
+ # Purchase a Reserved Instance.
130
+ # Returns ReservedInstancesId value.
131
+ #
132
+ # ec2.purchase_reserved_instances_offering('e5a2ff3b-f6eb-4b4e-83f8-b879d7060257', 3) # => '4b2293b4-5813-4cc8-9ce3-1957fc1dcfc8'
133
+ #
134
+ def purchase_reserved_instances_offering(reserved_instances_offering_id, instance_count=1, options={})
135
+ options[:options] ||= {}
136
+ options[:options][:api_version] ||= RESERVED_INSTANCE_API_VERSION
137
+
138
+ api_params = { 'ReservedInstancesOfferingId' => reserved_instances_offering_id,
139
+ 'InstanceCount' => instance_count }
140
+
141
+ link = generate_request("PurchaseReservedInstancesOffering", api_params, options)
142
+ request_info(link, QEc2PurchaseReservedInstancesOfferingParser.new)
143
+ rescue Exception
144
+ on_exception
145
+ end
146
+
147
+ #-----------------------------------------------------------------
148
+ # PARSERS: ReservedInstances
149
+ #-----------------------------------------------------------------
150
+
151
+ class QEc2DescribeReservedInstancesParser < RightAWSParser #:nodoc:
152
+ def tagstart(name, attributes)
153
+ case full_tag_name
154
+ when %r{/recurringCharges/item$} then @recurring_charge = {}
155
+ when %r{/tagSet/item$} then @aws_tag = {}
156
+ when %r{/reservedInstancesSet/item$} then @item = { :tags=> {} }
157
+ end
158
+ end
159
+ def tagend(name)
160
+ case name
161
+ when 'reservedInstancesId' then @item[:aws_id] = @text
162
+ when 'instanceType' then @item[:aws_instance_type] = @text
163
+ when 'availabilityZone' then @item[:aws_availability_zone] = @text
164
+ when 'duration' then @item[:aws_duration] = @text.to_i
165
+ when 'usagePrice' then @item[:aws_usage_price] = @text.to_f
166
+ when 'fixedPrice' then @item[:aws_fixed_price] = @text.to_f
167
+ when 'instanceCount' then @item[:aws_instance_count] = @text.to_i
168
+ when 'productDescription' then @item[:aws_product_description] = @text
169
+ when 'state' then @item[:aws_state] = @text
170
+ when 'start' then @item[:aws_start] = @text
171
+ when 'instanceTenancy' then @item[:instance_tenancy] = @text
172
+ when 'currencyCode' then @item[:currency_code] = @text
173
+ when 'offeringType' then @item[:offering_type] = @text
174
+ else
175
+ case full_tag_name
176
+ when %r{/tagSet/item/key$} then @aws_tag[:key] = @text
177
+ when %r{/tagSet/item/value$} then @aws_tag[:value] = @text
178
+ when %r{/tagSet/item$} then @item[:tags][@aws_tag[:key]] = @aws_tag[:value]
179
+ when %r{/recurringCharges/item/frequency$} then @recurring_charge[:frequency] = @text
180
+ when %r{/recurringCharges/item/amount$} then @recurring_charge[:amount] = @text
181
+ when %r{/recurringCharges/item$} then (@item[:recurring_charges] ||= []) << @recurring_charge
182
+ when %r{/reservedInstancesSet/item$} then @result << @item
183
+ end
184
+ end
185
+ end
186
+ def reset
187
+ @result = []
188
+ end
189
+ end
190
+
191
+ class QEc2DescribeReservedInstancesOfferingsParser < RightAWSParser #:nodoc:
192
+ def tagstart(name, attributes)
193
+ case full_tag_name
194
+ when %r{/pricingDetailsSet/item$} then @pricing_details = {}
195
+ when %r{/recurringCharges/item$} then @recurring_charge = {}
196
+ when %r{/reservedInstancesOfferingsSet/item$} then @item = {}
197
+ end
198
+ end
199
+ def tagend(name)
200
+ case name
201
+ when 'nextToken' then @result[:next_token] = @text
202
+ when 'reservedInstancesOfferingId' then @item[:aws_id] = @text
203
+ when 'instanceType' then @item[:aws_instance_type] = @text
204
+ when 'availabilityZone' then @item[:aws_availability_zone] = @text
205
+ when 'duration' then @item[:aws_duration] = @text.to_i
206
+ when 'usagePrice' then @item[:aws_usage_price] = @text.to_f
207
+ when 'fixedPrice' then @item[:aws_fixed_price] = @text.to_f
208
+ when 'instanceTenancy' then @item[:instance_tenancy] = @text
209
+ when 'currencyCode' then @item[:currency_code] = @text
210
+ when 'productDescription' then @item[:aws_product_description] = @text
211
+ when 'offeringType' then @item[:offering_type] = @text
212
+ when 'marketplace' then @item[:marketplace] = (@text == 'true')
213
+ else
214
+ case full_tag_name
215
+ when %r{/recurringCharges/item/frequency$} then @recurring_charge[:frequency] = @text
216
+ when %r{/recurringCharges/item/amount$} then @recurring_charge[:amount] = @text
217
+ when %r{/recurringCharges/item$} then (@item[:recurring_charges] ||= []) << @recurring_charge
218
+ when %r{/pricingDetailsSet/item/price$} then @pricing_details[:price] = @text
219
+ when %r{/pricingDetailsSet/item/count$} then @pricing_details[:count] = @text
220
+ when %r{/pricingDetailsSet/item$} then (@item[:pricing_details_set] ||= []) << @pricing_details
221
+ when %r{/reservedInstancesOfferingsSet/item$} then @result[:items] << @item
222
+ end
223
+ end
224
+ end
225
+ def reset
226
+ @result = { :items => [] }
227
+ end
228
+ end
229
+
230
+ class QEc2PurchaseReservedInstancesOfferingParser < RightAWSParser #:nodoc:
231
+ def tagend(name)
232
+ if name == 'reservedInstancesId'
233
+ @result = @text
234
+ end
235
+ end
236
+ def reset
237
+ @result = ''
238
+ end
239
+ end
240
+
241
+ end
242
+
243
+ end
@@ -0,0 +1,496 @@
1
+ #
2
+ # Copyright (c) 2010 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
+ # Security groups
30
+ #-----------------------------------------------------------------
31
+
32
+ # Retrieve Security Groups information.
33
+ # Options: By default this methods expects security group ids but if you wanna pass their names then :describe_by => :group_name option must be set.
34
+ #
35
+ # Accepts a list of security groups and/or a set of filters as the last parameter.
36
+ #
37
+ # Filters: description, group-name, ip-permission.cidr, ip-permission.from-port, ip-permission.group-name,
38
+ # ip-permission.protocol, ip-permission.to-port, ip-permission.user-id, owner-id
39
+ #
40
+ # # Amazon cloud:
41
+ # ec2 = Rightscale::Ec2.new(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY)
42
+ # ec2.describe_security_groups #=>
43
+ # [{:aws_perms=>
44
+ # [{:protocol=>"-1", :cidr_ips=>"0.0.0.0/0", :direction=>:egress},
45
+ # {:protocol=>"tcp",
46
+ # :cidr_ips=>"127.0.0.2/32",
47
+ # :direction=>:egress,
48
+ # :from_port=>"1111",
49
+ # :to_port=>"1111"},
50
+ # {:protocol=>"tcp",
51
+ # :cidr_ips=>"127.0.0.1/32",
52
+ # :direction=>:egress,
53
+ # :from_port=>"1111",
54
+ # :to_port=>"1111"}],
55
+ # :aws_group_name=>"kd-vpc-egress-test-1",
56
+ # :vpc_id=>"vpc-e16cf988",
57
+ # :aws_description=>"vpc test",
58
+ # :aws_owner=>"826693181925",
59
+ # :group_id=>"sg-b72032db"}]
60
+ #
61
+ # # Describe by group ids
62
+ # ec2.describe_security_groups("sg-a0b85dc9", "sg-00b05d39", "sg-a1b86dc8")
63
+ #
64
+ # # Describe by group names
65
+ # ec2.describe_security_groups("default", "default1", "kd", :describe_by => :group_name)
66
+ #
67
+ # # Eucalyptus cloud:
68
+ # ec2 = Rightscale::Ec2.new(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, :eucalyptus => true)
69
+ # ec2.describe_security_groups #=>
70
+ # [{:aws_perms=>
71
+ # [{:to_port=>"65535",
72
+ # :group_name=>"default",
73
+ # :protocol=>"tcp",
74
+ # :owner=>"048291609141",
75
+ # :from_port=>"1"},
76
+ # {:to_port=>"65535",
77
+ # :group_name=>"default",
78
+ # :protocol=>"udp",
79
+ # :owner=>"048291609141",
80
+ # :from_port=>"1"},
81
+ # {:to_port=>"-1",
82
+ # :group_name=>"default",
83
+ # :protocol=>"icmp",
84
+ # :owner=>"048291609141",
85
+ # :from_port=>"-1"},
86
+ # {:to_port=>"22",
87
+ # :protocol=>"tcp",
88
+ # :from_port=>"22",
89
+ # :cidr_ip=>"0.0.0.0/0"},
90
+ # {:to_port=>"9997",
91
+ # :protocol=>"tcp",
92
+ # :from_port=>"9997",
93
+ # :cidr_ip=>"0.0.0.0/0"}],
94
+ # :aws_group_name=>"photo_us",
95
+ # :aws_description=>"default group",
96
+ # :aws_owner=>"826693181925"}]
97
+ #
98
+ # ec2.describe_security_groups(:filters => {'ip-permission.from-port' => '22'})
99
+ #
100
+ # P.S. filters: http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-DescribeSecurityGroups.html
101
+ #
102
+ def describe_security_groups(*list_and_options)
103
+ list, options = AwsUtils::split_items_and_params(list_and_options)
104
+ describe_by = options.delete(:describe_by) == :group_name ? 'GroupName' : 'GroupId'
105
+ describe_resources_with_list_and_options('DescribeSecurityGroups', describe_by, QEc2DescribeSecurityGroupsParser, list_and_options) do |parser|
106
+ result = []
107
+ parser.result.each do |item|
108
+ result_item = { :aws_owner => item[:owner_id],
109
+ :aws_group_name => item[:group_name],
110
+ :aws_description => item[:group_description] }
111
+ result_item[:group_id] = item[:group_id] unless item[:group_id].right_blank?
112
+ result_item[:vpc_id] = item[:vpc_id] unless item[:vpc_id].right_blank?
113
+ aws_perms = []
114
+ item[:ip_permissions].each do |permission|
115
+ result_perm = {}
116
+ result_perm[:from_port] = permission[:from_port] unless permission[:from_port].right_blank?
117
+ result_perm[:to_port] = permission[:to_port] unless permission[:to_port].right_blank?
118
+ result_perm[:protocol] = permission[:ip_protocol]
119
+ result_perm[:direction] = permission[:direction]
120
+ # IP permissions
121
+ Array(permission[:ip_ranges]).each do |ip_range|
122
+ perm = result_perm.dup
123
+ # Mhhh... For Eucalyptus we somehow get used to use ":cidr_ip" instead of ":cidr_ips"...
124
+ if @params[:eucalyptus] then perm[:cidr_ip] = ip_range
125
+ else perm[:cidr_ips] = ip_range
126
+ end
127
+ aws_perms << perm
128
+ end
129
+ # Group permissions
130
+ Array(permission[:groups]).each do |group|
131
+ perm = result_perm.dup
132
+ perm[:group_name] = group[:group_name] unless group[:group_name].right_blank?
133
+ perm[:group_id] = group[:group_id] unless group[:group_id].right_blank?
134
+ perm[:owner] = group[:user_id] unless group[:user_id].right_blank?
135
+ aws_perms << perm
136
+ end
137
+ end
138
+ result_item[:aws_perms] = aws_perms.uniq
139
+ result << result_item
140
+ end
141
+ result
142
+ end
143
+ end
144
+
145
+ def describe_security_groups_by_name(*list)
146
+ describe_security_groups(list, :describe_by => :group_name)
147
+ end
148
+
149
+ # Create new Security Group. Returns +true+ or an exception.
150
+ # Options: :vpc_id
151
+ #
152
+ # ec2.create_security_group('default-1',"Default allowing SSH, HTTP, and HTTPS ingress") #=>
153
+ # { :group_id=>"sg-f0227599", :return=>true }
154
+ #
155
+ # ec2.create_security_group('default-2',"my VPC group", :vpc_id => 'vpc-e16c0000') #=>
156
+ # { :group_id=>"sg-76d1c31a", :return=>true }
157
+ #
158
+ def create_security_group(name, description = nil, options = {})
159
+ options = options.dup
160
+ options[:group_name] = name
161
+ options[:group_description] = description.right_blank? ? '-' : description # EC2 rejects an empty description...
162
+ link = generate_request("CreateSecurityGroup", map_api_keys_and_values(options, :group_name, :group_description, :vpc_id))
163
+ request_info(link, QEc2CreateSecurityGroupsParser.new(:logger => @logger))
164
+ rescue Exception
165
+ on_exception
166
+ end
167
+
168
+ # Remove Security Group. Returns +true+ or an exception.
169
+ # Options: :group_name, :group_id
170
+ #
171
+ # # Delete security group by group_id:
172
+ # ec2.delete_security_group('sg-90054ef9') #=> true
173
+ # ec2.delete_security_group(:group_id => 'sg-90054ef9') #=> true
174
+ #
175
+ # # Delete security group by name (EC2 only):
176
+ # ec2.delete_security_group(:group_name => 'my-group']) #=> true
177
+ #
178
+ def delete_security_group(group_id_or_options={})
179
+ options = group_id_or_options.is_a?(Hash) ? group_id_or_options : { :group_id => group_id_or_options }
180
+ link = generate_request("DeleteSecurityGroup", map_api_keys_and_values(options, :group_name, :group_id))
181
+ request_info(link, RightBoolResponseParser.new(:logger => @logger))
182
+ rescue Exception
183
+ on_exception
184
+ end
185
+
186
+ def grant_security_group_ingress(group_id, permissions)
187
+ modify_security_group(:grant, :ingress, group_id, permissions)
188
+ end
189
+
190
+ def revoke_security_group_ingress(group_id, permissions)
191
+ modify_security_group(:revoke, :ingress, group_id, permissions)
192
+ end
193
+
194
+ def grant_security_group_egress(group_id, permissions)
195
+ modify_security_group(:grant, :egress, group_id, permissions)
196
+ end
197
+
198
+ def revoke_security_group_egress(group_id, permissions)
199
+ modify_security_group(:revoke, :egress, group_id, permissions)
200
+ end
201
+
202
+ # Modify AWS security group permissions.
203
+ #
204
+ # Options:
205
+ # action - :authorize (or :grant) | :revoke (or :remove)
206
+ # direction - :ingress | :egress
207
+ # group_name - security group name
208
+ # permissions - a combination of options below:
209
+ # # Ports:
210
+ # :from_port => from port
211
+ # :to_port => to port
212
+ # :port => set both :from_port and to_port with the same value
213
+ # # Protocol
214
+ # :protocol => :tcp | :udp | :icmp | -1
215
+ # # or (ingress)
216
+ # :groups => { UserId1 => GroupId1, UserName2 => GroupId2 }
217
+ # :groups => [ [ UserId1, GroupId1 ], [ UserName2 => GroupId2 ] ]
218
+ # # or (egress)
219
+ # :groups => [ GroupId1, GroupId2 ]
220
+ # # CidrIp(s)
221
+ # :cidr_ip => '0.0.0.0/0'
222
+ # :cidr_ips => ['1.1.1.1/1', '2.2.2.2/2']
223
+ #
224
+ # # CidrIP based permissions:
225
+ #
226
+ # ec2.modify_security_group(:authorize, :ingress, 'sg-75d1c319',
227
+ # :cidr_ip => "127.0.0.0/31",
228
+ # :port => 811,
229
+ # :protocol => 'tcp' ) #=> true
230
+ #
231
+ # ec2.modify_security_group(:revoke, :ingress, 'sg-75d1c319',
232
+ # :cidr_ips => ["127.0.0.1/32", "127.0.0.2/32"],
233
+ # :port => 812,
234
+ # :protocol => 'tcp' ) #=> true
235
+ #
236
+ # # Group based permissions:
237
+ #
238
+ # ec2.modify_security_group(:authorize, :ingress, 'sg-75d1c319',
239
+ # :groups => { "586789340000" => "sg-75d1c300",
240
+ # "635201710000" => "sg-75d1c301" },
241
+ # :port => 801,
242
+ # :protocol => 'tcp' ) #=> true
243
+ #
244
+ # ec2.modify_security_group(:revoke, :ingress, 'sg-75d1c319',
245
+ # :groups => [[ "586789340000", "sg-75d1c300" ],
246
+ # [ "586789340000", "sg-75d1c302" ]],
247
+ # :port => 809,
248
+ # :protocol => 'tcp' ) #=> true
249
+ #
250
+ # # +Permissions+ can be an array of permission hashes:
251
+ #
252
+ # ec2.modify_security_group(:authorize, :ingress, 'sg-75d1c319',
253
+ # [{ :groups => { "586789340000" => "sg-75d1c300",
254
+ # "635201710000" => "sg-75d1c301" },
255
+ # :port => 803,
256
+ # :protocol => 'tcp'},
257
+ # { :cidr_ips => ["127.0.0.1/32", "127.0.0.2/32"],
258
+ # :port => 812,
259
+ # :protocol => 'tcp' }]) #=> true
260
+ #
261
+ def modify_security_group(action, direction, group_id, permissions)
262
+ hash = {}
263
+ raise "Unknown action #{action.inspect}!" unless [:authorize, :grant, :revoke, :remove].include?(action)
264
+ raise "Unknown direction #{direction.inspect}!" unless [:ingress, :egress].include?(direction)
265
+ # Remote action
266
+ remote_action = case action
267
+ when :authorize, :grant then direction == :ingress ? "AuthorizeSecurityGroupIngress" : "AuthorizeSecurityGroupEgress"
268
+ when :revoke, :remove then direction == :ingress ? "RevokeSecurityGroupIngress" : "RevokeSecurityGroupEgress"
269
+ end
270
+ # Group Name
271
+ hash["GroupId"] = group_id
272
+ # Permissions
273
+ permissions = [permissions] unless permissions.is_a?(Array)
274
+ permissions.each_with_index do |permission, idx|
275
+ pid = idx+1
276
+ # Protocol
277
+ hash["IpPermissions.#{pid}.IpProtocol"] = permission[:protocol]
278
+ # Port
279
+ unless permission[:port].right_blank?
280
+ hash["IpPermissions.#{pid}.FromPort"] = permission[:port]
281
+ hash["IpPermissions.#{pid}.ToPort"] = permission[:port]
282
+ else
283
+ hash["IpPermissions.#{pid}.FromPort"] = permission[:from_port]
284
+ hash["IpPermissions.#{pid}.ToPort"] = permission[:to_port]
285
+ end
286
+ # Groups
287
+ case direction
288
+ when :ingress
289
+ # :groups => {UserId1 => GroupId1, ... UserIdN => GroupIdN}
290
+ # or (this allows using same UserId multiple times )
291
+ # :groups => [[UserId1, GroupId1], ... [UserIdN, GroupIdN]]
292
+ # or even (unset user is == current account user)
293
+ # :groups => [GroupId1, GroupId2, ... GroupIdN]
294
+ # :groups => [[UserId1, GroupId1], GroupId2, ... GroupIdN, ... [UserIdM, GroupIdM]]
295
+ #
296
+ index = 1
297
+ unless permission[:group_names].right_blank?
298
+ owner_and_groups = []
299
+ groups_only = []
300
+ Array(permission[:group_names]).each do |item|
301
+ if item.is_a?(Array) && item.size == 2
302
+ owner_and_groups << item
303
+ else
304
+ groups_only << item
305
+ end
306
+ end
307
+ hash.merge!(amazonize_list( ["IpPermissions.#{pid}.Groups.?.UserId", "IpPermissions.#{pid}.Groups.?.GroupName"], owner_and_groups, :index => index ))
308
+ index += owner_and_groups.size
309
+ groups_only = groups_only.flatten
310
+ hash.merge!(amazonize_list( "IpPermissions.#{pid}.Groups.?.GroupName", groups_only, :index => index ))
311
+ index += groups_only.size
312
+ end
313
+ unless permission[:groups].right_blank?
314
+ owner_and_groups = []
315
+ groups_only = []
316
+ Array(permission[:groups]).each do |item|
317
+ if item.is_a?(Array) && item.size == 2
318
+ owner_and_groups << item
319
+ else
320
+ groups_only << item
321
+ end
322
+ end
323
+ hash.merge!(amazonize_list( ["IpPermissions.#{pid}.Groups.?.UserId", "IpPermissions.#{pid}.Groups.?.GroupId"], owner_and_groups, :index => index ))
324
+ index += owner_and_groups.size
325
+ groups_only = groups_only.flatten
326
+ hash.merge!(amazonize_list( "IpPermissions.#{pid}.Groups.?.GroupId", groups_only, :index => index ))
327
+ end
328
+ when :egress
329
+ # :groups => [GroupId1, ... GroupIdN]
330
+ hash.merge!(amazonize_list( "IpPermissions.#{pid}.Groups.?.GroupId", permission[:groups] ))
331
+ end
332
+ # CidrIp(s)
333
+ cidr_ips = permission[:cidr_ips] unless permission[:cidr_ips].right_blank?
334
+ cidr_ips ||= permission[:cidr_ip] unless permission[:cidr_ip].right_blank?
335
+ hash.merge!(amazonize_list("IpPermissions.1.IpRanges.?.CidrIp", cidr_ips))
336
+ end
337
+ #
338
+ link = generate_request(remote_action, hash)
339
+ request_info(link, RightBoolResponseParser.new(:logger => @logger))
340
+ rescue Exception
341
+ on_exception
342
+ end
343
+
344
+ #-----------------------------------------------------------------
345
+ # Eucalyptus
346
+ #-----------------------------------------------------------------
347
+
348
+ # Edit AWS/Eucaliptus security group permissions.
349
+ #
350
+ # Options:
351
+ # action - :authorize (or :grant) | :revoke (or :remove)
352
+ # group_name - security group name
353
+ # permissions - a combination of options below:
354
+ # :source_group_owner => UserId
355
+ # :source_group => GroupName
356
+ # :from_port => from port
357
+ # :to_port => to port
358
+ # :port => set both :from_port and to_port with the same value
359
+ # :protocol => :tcp | :udp | :icmp
360
+ # :cidr_ip => '0.0.0.0/0'
361
+ #
362
+ # ec2.edit_security_group( :grant,
363
+ # 'kd-sg-test',
364
+ # :source_group => "sketchy",
365
+ # :source_group_owner => "600000000006",
366
+ # :protocol => 'tcp',
367
+ # :port => '80',
368
+ # :cidr_ip => '127.0.0.1/32') #=> true
369
+ #
370
+ # P.S. This method is deprecated for AWS and but still good for Eucaliptus clouds.
371
+ # Use +modify_security_group_ingress+ method for AWS clouds.
372
+ #
373
+ def edit_security_group(action, group_name, params)
374
+ hash = {}
375
+ case action
376
+ when :authorize, :grant then action = "AuthorizeSecurityGroupIngress"
377
+ when :revoke, :remove then action = "RevokeSecurityGroupIngress"
378
+ else raise "Unknown action #{action.inspect}!"
379
+ end
380
+ hash['GroupName'] = group_name
381
+ hash['SourceSecurityGroupName'] = params[:source_group] unless params[:source_group].right_blank?
382
+ hash['IpProtocol'] = params[:protocol] unless params[:protocol].right_blank?
383
+ unless params[:source_group_owner].right_blank?
384
+ # Do remove dashes only if the source owner is in format of "7011-0219-8268"
385
+ source_group_owner = params[:source_group_owner].to_s
386
+ source_group_owner.gsub!(/-/,'') if source_group_owner[/^\d{4}-\d{4}-\d{4}$/]
387
+ hash['SourceSecurityGroupOwnerId'] = source_group_owner
388
+ end
389
+ unless params[:port].right_blank?
390
+ hash['FromPort'] = params[:port]
391
+ hash['ToPort'] = params[:port]
392
+ end
393
+ hash['FromPort'] = params[:from_port] unless params[:from_port].right_blank?
394
+ hash['ToPort'] = params[:to_port] unless params[:to_port].right_blank?
395
+ hash['CidrIp'] = params[:cidr_ip] unless params[:cidr_ip].right_blank?
396
+ #
397
+ link = generate_request(action, hash)
398
+ request_info(link, RightBoolResponseParser.new(:logger => @logger))
399
+ rescue Exception
400
+ on_exception
401
+ end
402
+
403
+ # Authorize named ingress for security group. Allows instances that are member of someone
404
+ # else's security group to open connections to instances in my group.
405
+ #
406
+ # ec2.authorize_security_group_named_ingress('my_awesome_group', '7011-0219-8268', 'their_group_name') #=> true
407
+ #
408
+ def authorize_security_group_named_ingress(name, owner, group)
409
+ edit_security_group( :authorize, name, :source_group_owner => owner, :source_group => group)
410
+ end
411
+
412
+ # Revoke named ingress for security group.
413
+ #
414
+ # ec2.revoke_security_group_named_ingress('my_awesome_group', aws_user_id, 'another_group_name') #=> true
415
+ #
416
+ def revoke_security_group_named_ingress(name, owner, group)
417
+ edit_security_group( :revoke, name, :source_group_owner => owner, :source_group => group)
418
+ end
419
+
420
+ # Add permission to a security group. Returns +true+ or an exception. +protocol+ is one of :'tcp'|'udp'|'icmp'.
421
+ #
422
+ # ec2.authorize_security_group_IP_ingress('my_awesome_group', 80, 82, 'udp', '192.168.1.0/8') #=> true
423
+ # ec2.authorize_security_group_IP_ingress('my_awesome_group', -1, -1, 'icmp') #=> true
424
+ #
425
+ def authorize_security_group_IP_ingress(name, from_port, to_port, protocol='tcp', cidr_ip='0.0.0.0/0')
426
+ edit_security_group( :authorize, name, :from_port => from_port, :to_port => to_port, :protocol => protocol, :cidr_ip => cidr_ip )
427
+ end
428
+
429
+ # Remove permission from a security group. Returns +true+ or an exception. +protocol+ is one of :'tcp'|'udp'|'icmp' ('tcp' is default).
430
+ #
431
+ # ec2.revoke_security_group_IP_ingress('my_awesome_group', 80, 82, 'udp', '192.168.1.0/8') #=> true
432
+ #
433
+ def revoke_security_group_IP_ingress(name, from_port, to_port, protocol='tcp', cidr_ip='0.0.0.0/0')
434
+ edit_security_group( :revoke, name, :from_port => from_port, :to_port => to_port, :protocol => protocol, :cidr_ip => cidr_ip )
435
+ end
436
+
437
+ #-----------------------------------------------------------------
438
+ # PARSERS: Security Groups
439
+ #-----------------------------------------------------------------
440
+
441
+ class QEc2CreateSecurityGroupsParser < RightAWSParser #:nodoc:
442
+ def tagend(name)
443
+ case name
444
+ when 'groupId' then @result[:group_id] = @text
445
+ when 'return' then @result[:return] = @text == 'true'
446
+ end
447
+ end
448
+ def reset
449
+ @result = {}
450
+ end
451
+ end
452
+
453
+ class QEc2DescribeSecurityGroupsParser < RightAWSParser #:nodoc:
454
+ def tagstart(name, attributes)
455
+ if name == 'item'
456
+ case full_tag_name
457
+ when %r{securityGroupInfo/item$} then @item = { :ip_permissions => [] }
458
+ when %r{ipPermissions/item$} then @ip_perm = { :groups => [], :ip_ranges => [], :direction => :ingress }
459
+ when %r{ipPermissionsEgress/item$} then @ip_perm = { :groups => [], :ip_ranges => [], :direction => :egress }
460
+ when %r{ipPermissions(Egress)?/item/groups/item$} then @group = {}
461
+ end
462
+ end
463
+ end
464
+ def tagend(name)
465
+ case name
466
+ when 'ownerId' then @item[:owner_id] = @text
467
+ when 'groupDescription' then @item[:group_description] = @text
468
+ when 'vpcId' then @item[:vpc_id] = @text
469
+ else
470
+ case full_tag_name
471
+ when %r{securityGroupInfo/item/groupName$} then @item[:group_name] = @text
472
+ when %r{securityGroupInfo/item/groupId$} then @item[:group_id] = @text
473
+ # ipPermission[Egress]
474
+ when %r{ipPermissions(Egress)?/item/ipProtocol$} then @ip_perm[:ip_protocol] = @text
475
+ when %r{ipPermissions(Egress)?/item/fromPort$} then @ip_perm[:from_port] = @text
476
+ when %r{ipPermissions(Egress)?/item/toPort$} then @ip_perm[:to_port] = @text
477
+ when %r{ipPermissions(Egress)?/item/ipRanges/item/cidrIp$} then @ip_perm[:ip_ranges] << @text
478
+ # ipPermissions[Egress]/Groups
479
+ when %r{ipPermissions(Egress)?/item/groups/item/groupName$} then @group[:group_name] = @text
480
+ when %r{ipPermissions(Egress)?/item/groups/item/groupId$} then @group[:group_id] = @text
481
+ when %r{ipPermissions(Egress)?/item/groups/item/userId$} then @group[:user_id] = @text
482
+ # Sets
483
+ when %r{ipPermissions(Egress)?/item/groups/item$} then @ip_perm[:groups] << @group
484
+ when %r{ipPermissions/item$} then @item[:ip_permissions] << @ip_perm
485
+ when %r{ipPermissionsEgress/item$} then @item[:ip_permissions] << @ip_perm
486
+ when %r{securityGroupInfo/item$} then @result << @item
487
+ end
488
+ end
489
+ end
490
+ def reset
491
+ @result = []
492
+ end
493
+ end
494
+
495
+ end
496
+ end