right_aws 1.9.0 → 3.1.0

Sign up to get free protection for your applications and to get access to all the features.
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