aboisvert_aws 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. data/History.txt +329 -0
  2. data/Manifest.txt +61 -0
  3. data/README.txt +163 -0
  4. data/Rakefile +130 -0
  5. data/lib/acf/right_acf_interface.rb +549 -0
  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/benchmark_fix.rb +39 -0
  12. data/lib/awsbase/right_awsbase.rb +1343 -0
  13. data/lib/awsbase/support.rb +35 -0
  14. data/lib/awsbase/version.rb +9 -0
  15. data/lib/ec2/right_ec2.rb +541 -0
  16. data/lib/ec2/right_ec2_ebs.rb +481 -0
  17. data/lib/ec2/right_ec2_images.rb +444 -0
  18. data/lib/ec2/right_ec2_instances.rb +788 -0
  19. data/lib/ec2/right_ec2_monitoring.rb +70 -0
  20. data/lib/ec2/right_ec2_placement_groups.rb +108 -0
  21. data/lib/ec2/right_ec2_reserved_instances.rb +184 -0
  22. data/lib/ec2/right_ec2_security_groups.rb +491 -0
  23. data/lib/ec2/right_ec2_spot_instances.rb +422 -0
  24. data/lib/ec2/right_ec2_tags.rb +139 -0
  25. data/lib/ec2/right_ec2_vpc.rb +590 -0
  26. data/lib/ec2/right_ec2_vpc2.rb +381 -0
  27. data/lib/ec2/right_ec2_windows_mobility.rb +84 -0
  28. data/lib/elb/right_elb_interface.rb +573 -0
  29. data/lib/emr/right_emr_interface.rb +727 -0
  30. data/lib/iam/right_iam_access_keys.rb +71 -0
  31. data/lib/iam/right_iam_groups.rb +195 -0
  32. data/lib/iam/right_iam_interface.rb +341 -0
  33. data/lib/iam/right_iam_mfa_devices.rb +67 -0
  34. data/lib/iam/right_iam_users.rb +251 -0
  35. data/lib/rds/right_rds_interface.rb +1384 -0
  36. data/lib/right_aws.rb +86 -0
  37. data/lib/route_53/right_route_53_interface.rb +640 -0
  38. data/lib/s3/right_s3.rb +1138 -0
  39. data/lib/s3/right_s3_interface.rb +1278 -0
  40. data/lib/sdb/active_sdb.rb +1107 -0
  41. data/lib/sdb/right_sdb_interface.rb +762 -0
  42. data/lib/sns/right_sns_interface.rb +286 -0
  43. data/lib/sqs/right_sqs.rb +387 -0
  44. data/lib/sqs/right_sqs_gen2.rb +342 -0
  45. data/lib/sqs/right_sqs_gen2_interface.rb +523 -0
  46. data/lib/sqs/right_sqs_interface.rb +593 -0
  47. data/right_aws.gemspec +90 -0
  48. data/test/README.mdown +39 -0
  49. data/test/acf/test_helper.rb +2 -0
  50. data/test/acf/test_right_acf.rb +138 -0
  51. data/test/awsbase/test_helper.rb +2 -0
  52. data/test/awsbase/test_right_awsbase.rb +11 -0
  53. data/test/ec2/test_helper.rb +2 -0
  54. data/test/ec2/test_right_ec2.rb +107 -0
  55. data/test/elb/test_helper.rb +2 -0
  56. data/test/elb/test_right_elb.rb +43 -0
  57. data/test/http_connection.rb +87 -0
  58. data/test/rds/test_helper.rb +2 -0
  59. data/test/rds/test_right_rds.rb +120 -0
  60. data/test/route_53/fixtures/a_record.xml +18 -0
  61. data/test/route_53/fixtures/alias_record.xml +18 -0
  62. data/test/route_53/test_helper.rb +2 -0
  63. data/test/route_53/test_right_route_53.rb +141 -0
  64. data/test/s3/test_helper.rb +2 -0
  65. data/test/s3/test_right_s3.rb +528 -0
  66. data/test/s3/test_right_s3_stubbed.rb +97 -0
  67. data/test/sdb/test_active_sdb.rb +357 -0
  68. data/test/sdb/test_batch_put_attributes.rb +54 -0
  69. data/test/sdb/test_helper.rb +3 -0
  70. data/test/sdb/test_right_sdb.rb +253 -0
  71. data/test/sns/test_helper.rb +2 -0
  72. data/test/sns/test_right_sns.rb +153 -0
  73. data/test/sqs/test_helper.rb +2 -0
  74. data/test/sqs/test_right_sqs.rb +285 -0
  75. data/test/sqs/test_right_sqs_gen2.rb +264 -0
  76. data/test/test_credentials.rb +37 -0
  77. data/test/ts_right_aws.rb +15 -0
  78. metadata +257 -0
@@ -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,184 @@
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
+ # Reserved instances
30
+ #-----------------------------------------------------------------
31
+
32
+ # Retrieve reserved instances list.
33
+ #
34
+ # Accepts a list of reserved instances and/or a set of filters as the last parameter.
35
+ #
36
+ # Filters: availability-zone, duration, fixed-price, instance-type, product-description,
37
+ # reserved-instances-id, start, state, tag-key, tag-value, tag:key, usage-price
38
+ #
39
+ # ec2.describe_reserved_instances #=>
40
+ # [{:currency_code=>"USD",
41
+ # :aws_fixed_price=>350.0,
42
+ # :aws_availability_zone=>"us-east-1c",
43
+ # :aws_instance_count=>1,
44
+ # :tags=>{},
45
+ # :aws_id=>"4357912c-ad94-4f57-8625-15ca71a8e66d",
46
+ # :aws_product_description=>"Linux/UNIX",
47
+ # :aws_state=>"active",
48
+ # :aws_start=>"2010-03-18T20:39:39.569Z",
49
+ # :aws_duration=>94608000,
50
+ # :aws_instance_type=>"m1.small",
51
+ # :instance_tenancy=>"default",
52
+ # :aws_usage_price=>0.03}]
53
+ #
54
+ # ec2.describe_reserved_instances(:filters => {'availability-zone' => 'us-east-1a'})
55
+ #
56
+ # P.S. filters: http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/index.html?ApiReference-query-DescribeReservedInstances.html
57
+ #
58
+ def describe_reserved_instances(*list_and_options)
59
+ describe_resources_with_list_and_options('DescribeReservedInstances', 'ReservedInstancesId', QEc2DescribeReservedInstancesParser, list_and_options)
60
+ end
61
+
62
+ # Retrieve reserved instances offerings.
63
+ #
64
+ # Accepts a list of reserved instances offerings and/or a set of filters as the last parameter.
65
+ #
66
+ # Filters: availability-zone, duration, fixed-price, instance-type, product-description, reserved-instances-offering-id, usage-price
67
+ #
68
+ # ec2.describe_reserved_instances_offerings #=>
69
+ # [{:currency_code=>"USD",
70
+ # :aws_fixed_price=>700.0,
71
+ # :aws_id=>"248e7b75-933c-451b-b126-be25865e02a5",
72
+ # :aws_product_description=>"Linux/UNIX",
73
+ # :aws_instance_type=>"c1.medium",
74
+ # :aws_duration=>94608000,
75
+ # :instance_tenancy=>"default",
76
+ # :aws_usage_price=>0.06,
77
+ # :aws_availability_zone=>"us-east-1a"},
78
+ # {:currency_code=>"USD",
79
+ # :aws_fixed_price=>700.0,
80
+ # :aws_id=>"c48ab04c-7e03-46b2-891a-2df1116e51a3",
81
+ # :aws_product_description=>"Linux/UNIX (Amazon VPC)",
82
+ # :aws_instance_type=>"c1.medium",
83
+ # :aws_duration=>94608000,
84
+ # :instance_tenancy=>"default",
85
+ # :aws_usage_price=>0.06,
86
+ # :aws_availability_zone=>"us-east-1a"}, ... ]
87
+ #
88
+ # ec2.describe_reserved_instances_offerings(:filters => {'availability-zone' => 'us-east-1c'})
89
+ #
90
+ # P.S. filters: http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/index.html?ApiReference-query-DescribeReservedInstancesOfferings.html
91
+ #
92
+ def describe_reserved_instances_offerings(*list_and_options)
93
+ describe_resources_with_list_and_options('DescribeReservedInstancesOfferings', 'ReservedInstancesOfferingId', QEc2DescribeReservedInstancesOfferingsParser, list_and_options)
94
+ end
95
+
96
+ # Purchase a Reserved Instance.
97
+ # Returns ReservedInstancesId value.
98
+ #
99
+ # ec2.purchase_reserved_instances_offering('e5a2ff3b-f6eb-4b4e-83f8-b879d7060257', 3) # => '4b2293b4-5813-4cc8-9ce3-1957fc1dcfc8'
100
+ #
101
+ def purchase_reserved_instances_offering(reserved_instances_offering_id, instance_count=1)
102
+ link = generate_request("PurchaseReservedInstancesOffering", { 'ReservedInstancesOfferingId' => reserved_instances_offering_id,
103
+ 'InstanceCount' => instance_count })
104
+ request_info(link, QEc2PurchaseReservedInstancesOfferingParser.new)
105
+ rescue Exception
106
+ on_exception
107
+ end
108
+
109
+ #-----------------------------------------------------------------
110
+ # PARSERS: ReservedInstances
111
+ #-----------------------------------------------------------------
112
+
113
+ class QEc2DescribeReservedInstancesParser < RightAWSParser #:nodoc:
114
+ def tagstart(name, attributes)
115
+ case full_tag_name
116
+ when %r{/reservedInstancesSet/item$} then @item = { :tags => {} }
117
+ when %r{/tagSet/item$} then @aws_tag = {}
118
+ end
119
+ end
120
+ def tagend(name)
121
+ case name
122
+ when 'reservedInstancesId' then @item[:aws_id] = @text
123
+ when 'instanceType' then @item[:aws_instance_type] = @text
124
+ when 'availabilityZone' then @item[:aws_availability_zone] = @text
125
+ when 'duration' then @item[:aws_duration] = @text.to_i
126
+ when 'usagePrice' then @item[:aws_usage_price] = @text.to_f
127
+ when 'fixedPrice' then @item[:aws_fixed_price] = @text.to_f
128
+ when 'instanceCount' then @item[:aws_instance_count] = @text.to_i
129
+ when 'productDescription' then @item[:aws_product_description] = @text
130
+ when 'state' then @item[:aws_state] = @text
131
+ when 'start' then @item[:aws_start] = @text
132
+ when 'instanceTenancy' then @item[:instance_tenancy] = @text
133
+ when 'currencyCode' then @item[:currency_code] = @text
134
+ else
135
+ case full_tag_name
136
+ when %r{/tagSet/item/key$} then @aws_tag[:key] = @text
137
+ when %r{/tagSet/item/value$} then @aws_tag[:value] = @text
138
+ when %r{/tagSet/item$} then @item[:tags][@aws_tag[:key]] = @aws_tag[:value]
139
+ when %r{/reservedInstancesSet/item$} then @result << @item
140
+ end
141
+ end
142
+ end
143
+ def reset
144
+ @result = []
145
+ end
146
+ end
147
+
148
+ class QEc2DescribeReservedInstancesOfferingsParser < RightAWSParser #:nodoc:
149
+ def tagstart(name, attributes)
150
+ @item = {} if name == 'item'
151
+ end
152
+ def tagend(name)
153
+ case name
154
+ when 'reservedInstancesOfferingId' then @item[:aws_id] = @text
155
+ when 'instanceType' then @item[:aws_instance_type] = @text
156
+ when 'availabilityZone' then @item[:aws_availability_zone] = @text
157
+ when 'duration' then @item[:aws_duration] = @text.to_i
158
+ when 'usagePrice' then @item[:aws_usage_price] = @text.to_f
159
+ when 'fixedPrice' then @item[:aws_fixed_price] = @text.to_f
160
+ when 'instanceTenancy' then @item[:instance_tenancy] = @text
161
+ when 'currencyCode' then @item[:currency_code] = @text
162
+ when 'productDescription' then @item[:aws_product_description] = @text
163
+ when 'item' then @result << @item
164
+ end
165
+ end
166
+ def reset
167
+ @result = []
168
+ end
169
+ end
170
+
171
+ class QEc2PurchaseReservedInstancesOfferingParser < RightAWSParser #:nodoc:
172
+ def tagend(name)
173
+ if name == 'reservedInstancesId'
174
+ @result = @text
175
+ end
176
+ end
177
+ def reset
178
+ @result = ''
179
+ end
180
+ end
181
+
182
+ end
183
+
184
+ end
@@ -0,0 +1,491 @@
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['SourceSecurityGroupOwnerId'] = params[:source_group_owner].to_s.gsub(/-/,'') unless params[:source_group_owner].right_blank?
383
+ hash['IpProtocol'] = params[:protocol] unless params[:protocol].right_blank?
384
+ unless params[:port].right_blank?
385
+ hash['FromPort'] = params[:port]
386
+ hash['ToPort'] = params[:port]
387
+ end
388
+ hash['FromPort'] = params[:from_port] unless params[:from_port].right_blank?
389
+ hash['ToPort'] = params[:to_port] unless params[:to_port].right_blank?
390
+ hash['CidrIp'] = params[:cidr_ip] unless params[:cidr_ip].right_blank?
391
+ #
392
+ link = generate_request(action, hash)
393
+ request_info(link, RightBoolResponseParser.new(:logger => @logger))
394
+ rescue Exception
395
+ on_exception
396
+ end
397
+
398
+ # Authorize named ingress for security group. Allows instances that are member of someone
399
+ # else's security group to open connections to instances in my group.
400
+ #
401
+ # ec2.authorize_security_group_named_ingress('my_awesome_group', '7011-0219-8268', 'their_group_name') #=> true
402
+ #
403
+ def authorize_security_group_named_ingress(name, owner, group)
404
+ edit_security_group( :authorize, name, :source_group_owner => owner, :source_group => group)
405
+ end
406
+
407
+ # Revoke named ingress for security group.
408
+ #
409
+ # ec2.revoke_security_group_named_ingress('my_awesome_group', aws_user_id, 'another_group_name') #=> true
410
+ #
411
+ def revoke_security_group_named_ingress(name, owner, group)
412
+ edit_security_group( :revoke, name, :source_group_owner => owner, :source_group => group)
413
+ end
414
+
415
+ # Add permission to a security group. Returns +true+ or an exception. +protocol+ is one of :'tcp'|'udp'|'icmp'.
416
+ #
417
+ # ec2.authorize_security_group_IP_ingress('my_awesome_group', 80, 82, 'udp', '192.168.1.0/8') #=> true
418
+ # ec2.authorize_security_group_IP_ingress('my_awesome_group', -1, -1, 'icmp') #=> true
419
+ #
420
+ def authorize_security_group_IP_ingress(name, from_port, to_port, protocol='tcp', cidr_ip='0.0.0.0/0')
421
+ edit_security_group( :authorize, name, :from_port => from_port, :to_port => to_port, :protocol => protocol, :cidr_ip => cidr_ip )
422
+ end
423
+
424
+ # Remove permission from a security group. Returns +true+ or an exception. +protocol+ is one of :'tcp'|'udp'|'icmp' ('tcp' is default).
425
+ #
426
+ # ec2.revoke_security_group_IP_ingress('my_awesome_group', 80, 82, 'udp', '192.168.1.0/8') #=> true
427
+ #
428
+ def revoke_security_group_IP_ingress(name, from_port, to_port, protocol='tcp', cidr_ip='0.0.0.0/0')
429
+ edit_security_group( :revoke, name, :from_port => from_port, :to_port => to_port, :protocol => protocol, :cidr_ip => cidr_ip )
430
+ end
431
+
432
+ #-----------------------------------------------------------------
433
+ # PARSERS: Security Groups
434
+ #-----------------------------------------------------------------
435
+
436
+ class QEc2CreateSecurityGroupsParser < RightAWSParser #:nodoc:
437
+ def tagend(name)
438
+ case name
439
+ when 'groupId' then @result[:group_id] = @text
440
+ when 'return' then @result[:return] = @text == 'true'
441
+ end
442
+ end
443
+ def reset
444
+ @result = {}
445
+ end
446
+ end
447
+
448
+ class QEc2DescribeSecurityGroupsParser < RightAWSParser #:nodoc:
449
+ def tagstart(name, attributes)
450
+ if name == 'item'
451
+ case full_tag_name
452
+ when %r{securityGroupInfo/item$} then @item = { :ip_permissions => [] }
453
+ when %r{ipPermissions/item$} then @ip_perm = { :groups => [], :ip_ranges => [], :direction => :ingress }
454
+ when %r{ipPermissionsEgress/item$} then @ip_perm = { :groups => [], :ip_ranges => [], :direction => :egress }
455
+ when %r{ipPermissions(Egress)?/item/groups/item$} then @group = {}
456
+ end
457
+ end
458
+ end
459
+ def tagend(name)
460
+ case name
461
+ when 'ownerId' then @item[:owner_id] = @text
462
+ when 'groupDescription' then @item[:group_description] = @text
463
+ when 'vpcId' then @item[:vpc_id] = @text
464
+ else
465
+ case full_tag_name
466
+ when %r{securityGroupInfo/item/groupName$} then @item[:group_name] = @text
467
+ when %r{securityGroupInfo/item/groupId$} then @item[:group_id] = @text
468
+ # ipPermission[Egress]
469
+ when %r{ipPermissions(Egress)?/item/ipProtocol$} then @ip_perm[:ip_protocol] = @text
470
+ when %r{ipPermissions(Egress)?/item/fromPort$} then @ip_perm[:from_port] = @text
471
+ when %r{ipPermissions(Egress)?/item/toPort$} then @ip_perm[:to_port] = @text
472
+ when %r{ipPermissions(Egress)?/item/ipRanges/item/cidrIp$} then @ip_perm[:ip_ranges] << @text
473
+ # ipPermissions[Egress]/Groups
474
+ when %r{ipPermissions(Egress)?/item/groups/item/groupName$} then @group[:group_name] = @text
475
+ when %r{ipPermissions(Egress)?/item/groups/item/groupId$} then @group[:group_id] = @text
476
+ when %r{ipPermissions(Egress)?/item/groups/item/userId$} then @group[:user_id] = @text
477
+ # Sets
478
+ when %r{ipPermissions(Egress)?/item/groups/item$} then @ip_perm[:groups] << @group
479
+ when %r{ipPermissions/item$} then @item[:ip_permissions] << @ip_perm
480
+ when %r{ipPermissionsEgress/item$} then @item[:ip_permissions] << @ip_perm
481
+ when %r{securityGroupInfo/item$} then @result << @item
482
+ end
483
+ end
484
+ end
485
+ def reset
486
+ @result = []
487
+ end
488
+ end
489
+
490
+ end
491
+ end