chef-provisioning-aws 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +2 -0
  3. data/lib/chef/provider/aws_auto_scaling_group.rb +30 -41
  4. data/lib/chef/provider/aws_dhcp_options.rb +70 -0
  5. data/lib/chef/provider/aws_ebs_volume.rb +182 -34
  6. data/lib/chef/provider/aws_eip_address.rb +63 -60
  7. data/lib/chef/provider/aws_key_pair.rb +18 -27
  8. data/lib/chef/provider/aws_launch_configuration.rb +50 -0
  9. data/lib/chef/provider/aws_route_table.rb +122 -0
  10. data/lib/chef/provider/aws_s3_bucket.rb +42 -49
  11. data/lib/chef/provider/aws_security_group.rb +252 -59
  12. data/lib/chef/provider/aws_sns_topic.rb +10 -26
  13. data/lib/chef/provider/aws_sqs_queue.rb +16 -38
  14. data/lib/chef/provider/aws_subnet.rb +85 -32
  15. data/lib/chef/provider/aws_vpc.rb +163 -23
  16. data/lib/chef/provisioning/aws_driver.rb +18 -1
  17. data/lib/chef/provisioning/aws_driver/aws_provider.rb +206 -0
  18. data/lib/chef/provisioning/aws_driver/aws_resource.rb +186 -0
  19. data/lib/chef/provisioning/aws_driver/aws_resource_with_entry.rb +114 -0
  20. data/lib/chef/provisioning/aws_driver/driver.rb +317 -255
  21. data/lib/chef/provisioning/aws_driver/resources.rb +8 -5
  22. data/lib/chef/provisioning/aws_driver/super_lwrp.rb +45 -0
  23. data/lib/chef/provisioning/aws_driver/version.rb +1 -1
  24. data/lib/chef/resource/aws_auto_scaling_group.rb +15 -13
  25. data/lib/chef/resource/aws_dhcp_options.rb +57 -0
  26. data/lib/chef/resource/aws_ebs_volume.rb +20 -22
  27. data/lib/chef/resource/aws_eip_address.rb +50 -25
  28. data/lib/chef/resource/aws_image.rb +20 -0
  29. data/lib/chef/resource/aws_instance.rb +20 -0
  30. data/lib/chef/resource/aws_internet_gateway.rb +16 -0
  31. data/lib/chef/resource/aws_key_pair.rb +6 -10
  32. data/lib/chef/resource/aws_launch_configuration.rb +15 -0
  33. data/lib/chef/resource/aws_load_balancer.rb +16 -0
  34. data/lib/chef/resource/aws_network_interface.rb +16 -0
  35. data/lib/chef/resource/aws_route_table.rb +76 -0
  36. data/lib/chef/resource/aws_s3_bucket.rb +8 -18
  37. data/lib/chef/resource/aws_security_group.rb +49 -19
  38. data/lib/chef/resource/aws_sns_topic.rb +14 -15
  39. data/lib/chef/resource/aws_sqs_queue.rb +16 -14
  40. data/lib/chef/resource/aws_subnet.rb +87 -17
  41. data/lib/chef/resource/aws_vpc.rb +137 -15
  42. data/spec/integration/aws_security_group_spec.rb +55 -0
  43. data/spec/spec_helper.rb +8 -2
  44. data/spec/support/aws_support.rb +211 -0
  45. metadata +33 -10
  46. data/lib/chef/provider/aws_launch_config.rb +0 -43
  47. data/lib/chef/provider/aws_provider.rb +0 -22
  48. data/lib/chef/provisioning/aws_driver/aws_profile.rb +0 -73
  49. data/lib/chef/resource/aws_launch_config.rb +0 -14
  50. data/lib/chef/resource/aws_resource.rb +0 -10
  51. data/spec/chef_zero_rspec_helper.rb +0 -8
  52. data/spec/unit/provider/aws_subnet_spec.rb +0 -67
  53. data/spec/unit/resource/aws_subnet_spec.rb +0 -23
@@ -1,39 +1,23 @@
1
- require 'chef/provider/aws_provider'
1
+ require 'chef/provisioning/aws_driver/aws_provider'
2
2
  require 'date'
3
3
 
4
- class Chef::Provider::AwsSnsTopic < Chef::Provider::AwsProvider
4
+ class Chef::Provider::AwsSnsTopic < Chef::Provisioning::AWSDriver::AWSProvider
5
5
 
6
- action :create do
7
- if existing_topic == nil
8
- converge_by "Creating new SNS topic #{fqn} in #{new_driver.aws_config.region}" do
9
- new_driver.sns.topics.create(fqn)
6
+ protected
10
7
 
11
- new_resource.created_at DateTime.now.to_s
12
- new_resource.save
13
- end
8
+ def create_aws_object
9
+ converge_by "Creating new SNS topic #{new_resource.name} in #{region}" do
10
+ new_resource.driver.sns.topics.create(new_resource.name)
14
11
  end
15
12
  end
16
13
 
17
- action :delete do
18
- if existing_topic
19
- converge_by "Deleting SNS topic #{fqn} in #{new_driver.aws_config.region}" do
20
- existing_topic.delete
21
- end
22
- end
23
-
24
- new_resource.delete
14
+ def update_aws_object(topic)
25
15
  end
26
16
 
27
- def existing_topic
28
- @existing_topic ||= begin
29
- new_driver.sns.topics.named(fqn)
30
- rescue
31
- nil
17
+ def destroy_aws_object(topic)
18
+ converge_by "Deleting SNS topic #{topic.name} in #{region}" do
19
+ topic.delete
32
20
  end
33
21
  end
34
22
 
35
- def id
36
- new_resource.topic_name
37
- end
38
-
39
23
  end
@@ -1,47 +1,25 @@
1
- require 'chef/provider/aws_provider'
2
- require 'date'
3
-
4
- class Chef::Provider::AwsSqsQueue < Chef::Provider::AwsProvider
5
-
6
- action :create do
7
- if existing_queue == nil
8
- converge_by "Creating new SQS queue #{fqn} in #{new_driver.aws_config.region}" do
9
- loop do
10
- begin
11
- new_driver.sqs.queues.create(fqn)
12
- break
13
- rescue AWS::SQS::Errors::QueueDeletedRecently
14
- sleep 5
15
- end
16
- end
17
-
18
- new_resource.created_at DateTime.now.to_s
19
- new_resource.save
1
+ require 'chef/provisioning/aws_driver/aws_provider'
2
+
3
+ class Chef::Provider::AwsSqsQueue < Chef::Provisioning::AWSDriver::AWSProvider
4
+
5
+ def create_aws_object
6
+ converge_by "create new SQS queue #{new_resource.name} in #{region}" do
7
+ # TODO need timeout here.
8
+ begin
9
+ new_resource.driver.sqs.queues.create(new_resource.name, new_resource.options || {})
10
+ rescue AWS::SQS::Errors::QueueDeletedRecently
11
+ sleep 5
12
+ retry
20
13
  end
21
14
  end
22
15
  end
23
16
 
24
- action :delete do
25
- if existing_queue
26
- converge_by "Deleting SQS queue #{fqn} in #{new_driver.aws_config.region}" do
27
- existing_queue.delete
28
- end
29
- end
30
-
31
- new_resource.delete
17
+ def update_aws_object(queue)
32
18
  end
33
19
 
34
- def existing_queue
35
- @existing_queue ||= begin
36
- new_driver.sqs.queues.named(fqn)
37
- rescue
38
- nil
20
+ def destroy_aws_object(queue)
21
+ converge_by "delete SQS queue #{new_resource.name} in #{region}" do
22
+ queue.delete
39
23
  end
40
24
  end
41
-
42
- # Fully qualified queue name (i.e luigi:us-east-1)
43
- def id
44
- new_resource.queue_name
45
- end
46
-
47
25
  end
@@ -1,52 +1,105 @@
1
- require 'chef/provider/aws_provider'
1
+ require 'chef/provisioning/aws_driver/aws_provider'
2
+ require 'chef/provisioning/aws_driver/aws_resource'
2
3
  require 'date'
4
+ require 'chef/resource/aws_vpc'
3
5
 
4
- class Chef::Provider::AwsSubnet < Chef::Provider::AwsProvider
6
+ class Chef::Provider::AwsSubnet < Chef::Provisioning::AWSDriver::AWSProvider
5
7
 
6
- action :create do
7
- fail "Can't create a Subnet without a CIDR block" if new_resource.cidr_block.nil?
8
+ def action_create
9
+ subnet = super
8
10
 
9
- if existing_subnet == nil
10
- converge_by "Creating new Subnet #{fqn} in VPC #{new_resource.vpc} in #{new_driver.aws_config.region}" do
11
- opts = { :vpc => vpc_id }
12
- opts[:availability_zone] = new_resource.availability_zone if new_resource.availability_zone
13
- subnet = new_driver.ec2.subnets.create(new_resource.cidr_block, opts)
14
- subnet.tags['Name'] = new_resource.name
15
- subnet.tags['VPC'] = new_resource.vpc
16
- new_resource.subnet_id subnet.id
17
- new_resource.save
18
- end
11
+ if new_resource.map_public_ip_on_launch != nil
12
+ update_map_public_ip_on_launch(subnet)
13
+ end
14
+
15
+ if new_resource.route_table != nil
16
+ update_route_table(subnet)
19
17
  end
20
18
  end
21
19
 
22
- action :delete do
23
- if existing_subnet
24
- converge_by "Deleting subnet #{fqn} in VPC #{new_resource.vpc} in #{new_driver.aws_config.region}" do
25
- existing_subnet.delete
26
- end
20
+ protected
21
+
22
+ def create_aws_object
23
+ cidr_block = new_resource.cidr_block
24
+ if !cidr_block
25
+ cidr_block = Chef::Resource::AwsVpc.get_aws_object(new_resource.vpc, resource: new_resource).cidr_block
27
26
  end
27
+ options = { :vpc => new_resource.vpc }
28
+ options[:availability_zone] = new_resource.availability_zone if new_resource.availability_zone
29
+ options = Chef::Provisioning::AWSDriver::AWSResource.lookup_options(options, resource: new_resource)
28
30
 
29
- new_resource.delete
31
+ converge_by "create new subnet #{new_resource.name} with CIDR #{cidr_block} in VPC #{new_resource.vpc} (#{options[:vpc]}) in #{region}" do
32
+ subnet = new_resource.driver.ec2.subnets.create(cidr_block, options)
33
+ subnet.tags['Name'] = new_resource.name
34
+ subnet.tags['VPC'] = new_resource.vpc
35
+ subnet
36
+ end
30
37
  end
31
38
 
32
- def vpc_id
33
- @vpc_id ||= begin
34
- new_driver.ec2.vpcs.with_tag('Name', new_resource.vpc).first
35
- rescue
36
- nil
39
+ def update_aws_object(subnet)
40
+ # Verify unmodifiable attributes of existing subnet
41
+ if new_resource.cidr_block && subnet.cidr_block != new_resource.cidr_block
42
+ raise "cidr_block for subnet #{new_resource.name} is #{new_resource.cidr_block}, but existing subnet (#{subnet.id})'s cidr_block is #{subnet.cidr_block}. Modification of subnet cidr_block is unsupported!"
43
+ end
44
+ vpc = Chef::Resource::AwsVpc.get_aws_object(new_resource.vpc, resource: new_resource)
45
+ if vpc && subnet.vpc != vpc
46
+ raise "vpc for subnet #{new_resource.name} is #{new_resource.vpc} (#{vpc.id}), but existing subnet (#{subnet.id})'s vpc is #{subnet.vpc.id}. Modification of subnet vpc is unsupported!"
47
+ end
48
+ if new_resource.availability_zone && subnet.availability_zone_name != new_resource.availability_zone
49
+ raise "availability_zone for subnet #{new_resource.name} is #{new_resource.availability_zone}, but existing subnet (#{subnet.id})'s availability_zone is #{subnet.availability_zone}. Modification of subnet availability_zone is unsupported!"
37
50
  end
38
51
  end
39
52
 
40
- def existing_subnet
41
- @subnet_id ||= begin
42
- new_driver.ec2.subnets.with_tag('Name', new_resource.name).first
43
- rescue
44
- nil
53
+ def destroy_aws_object(subnet)
54
+ converge_by "delete subnet #{new_resource.name} in VPC #{new_resource.vpc} in #{region}" do
55
+ subnet.delete
45
56
  end
46
57
  end
47
58
 
48
- def id
49
- new_resource.subnet_id
59
+ private
60
+
61
+ def update_map_public_ip_on_launch(subnet)
62
+ if !new_resource.map_public_ip_on_launch.nil?
63
+ subnet_desc = subnet.client.describe_subnets(subnet_ids: [ subnet.id ])[:subnet_set].first
64
+ if new_resource.map_public_ip_on_launch
65
+ if !subnet_desc[:map_public_ip_on_launch]
66
+ converge_by "turn on automatic public IPs for subnet #{subnet.id}" do
67
+ subnet.client.modify_subnet_attribute(subnet_id: subnet.id, map_public_ip_on_launch: { value: true })
68
+ end
69
+ end
70
+ else
71
+ if subnet_desc[:map_public_ip_on_launch]
72
+ converge_by "turn off automatic public IPs for subnet #{subnet.id}" do
73
+ subnet.client.modify_subnet_attribute(subnet_id: subnet.id, map_public_ip_on_launch: { value: false })
74
+ end
75
+ end
76
+ end
77
+ end
50
78
  end
51
79
 
80
+ def update_route_table(subnet)
81
+ if new_resource.route_table == :default_to_main
82
+ if !subnet.route_table_association.main?
83
+ converge_by "reset route table of subnet #{new_resource.name} to the VPC default" do
84
+ subnet.route_table = nil
85
+ end
86
+ end
87
+ else
88
+ route_table = Chef::Resource::AwsRouteTable.get_aws_object(new_resource.route_table, resource: new_resource)
89
+ current_route_table_association = subnet.route_table_association
90
+ if current_route_table_association.main?
91
+ # Even if the user sets the route table explicitly to the main route table,
92
+ # we have work to do here: we need to make the relationship explicit so that
93
+ # it won't be changed when the main route table of the VPC changes.
94
+ converge_by "set route table of subnet #{new_resource.name} to #{new_resource.route_table}" do
95
+ subnet.route_table = route_table
96
+ end
97
+ elsif current_route_table_association.route_table != route_table
98
+ # The route table is different now. Change it.
99
+ converge_by "change route table of subnet #{new_resource.name} to #{new_resource.route_table} (was #{current_route_table_association.route_table.id})" do
100
+ subnet.route_table = route_table
101
+ end
102
+ end
103
+ end
104
+ end
52
105
  end
@@ -1,42 +1,182 @@
1
- require 'chef/provider/aws_provider'
1
+ require 'chef/provisioning/aws_driver/aws_provider'
2
2
  require 'date'
3
3
 
4
- class Chef::Provider::AwsVpc < Chef::Provider::AwsProvider
4
+ class Chef::Provider::AwsVpc < Chef::Provisioning::AWSDriver::AWSProvider
5
5
 
6
- action :create do
7
- fail "Can't create a VPC without a CIDR block" if new_resource.cidr_block.nil?
6
+ def action_create
7
+ vpc = super
8
8
 
9
- if existing_vpc == nil
10
- converge_by "Creating new VPC #{fqn} in #{new_driver.aws_config.region}" do
11
- opts = { :instance_tenancy => :default}
12
- vpc = new_driver.ec2.vpcs.create(new_resource.cidr_block, opts)
13
- vpc.tags['Name'] = new_resource.name
14
- new_resource.vpc_id vpc.id
15
- new_resource.save
9
+ # Update DNS attributes
10
+ update_vpc_attributes(vpc)
11
+
12
+ #
13
+ # Attach/detach internet gateway
14
+ #
15
+ if !new_resource.internet_gateway.nil?
16
+ update_internet_gateway(vpc)
17
+ end
18
+
19
+ # Replace the main route table for the VPC
20
+ if !new_resource.main_route_table.nil?
21
+ main_route_table = update_main_route_table(vpc)
22
+ end
23
+
24
+ # Update the main route table
25
+ if !new_resource.main_routes.nil?
26
+ update_main_routes(vpc, main_route_table)
27
+ end
28
+
29
+ # Update DHCP options
30
+ if !new_resource.dhcp_options.nil?
31
+ update_dhcp_options(vpc)
32
+ end
33
+ end
34
+
35
+ protected
36
+
37
+ def create_aws_object
38
+ options = { }
39
+ options[:instance_tenancy] = new_resource.instance_tenancy if new_resource.instance_tenancy
40
+
41
+ converge_by "create new VPC #{new_resource.name} in #{region}" do
42
+ vpc = new_resource.driver.ec2.vpcs.create(new_resource.cidr_block, options)
43
+ vpc.tags['Name'] = new_resource.name
44
+ vpc
45
+ end
46
+ end
47
+
48
+ def update_aws_object(vpc)
49
+ if new_resource.instance_tenancy && new_resource.instance_tenancy != vpc.instance_tenancy
50
+ raise "Tenancy of VPC #{new_resource.name} is #{vpc.instance_tenancy}, but desired tenancy is #{new_resource.instance_tenancy}. Instance tenancy of VPCs cannot be changed!"
51
+ end
52
+ if new_resource.cidr_block && new_resource.cidr_block != vpc.cidr_block
53
+ raise "CIDR block of VPC #{new_resource.name} is #{vpc.cidr_block}, but desired CIDR block is #{new_resource.cidr_block}. VPC CIDR blocks cannot currently be changed!"
54
+ end
55
+ end
56
+
57
+ def destroy_aws_object(vpc)
58
+ # Detach or destroy the internet gateway
59
+ ig = vpc.internet_gateway
60
+ if ig
61
+ converge_by "detach Internet Gateway #{ig.id} in #{region} from VPC #{new_resource.name} (#{vpc.id}" do
62
+ ig.detach(vpc.id)
63
+ end
64
+ if ig.tags['OwnedByVPC'] == vpc.id
65
+ converge_by "destroy Internet Gateway #{ig.id} in #{region} (owned by VPC #{new_resource.name} (#{vpc.id}))" do
66
+ ig.delete
67
+ end
16
68
  end
17
69
  end
70
+
71
+ # TODO delete main route table & routes if they exist and we created them
72
+
73
+ converge_by "delete VPC #{new_resource.name} (#{vpc.id}) in #{region}" do
74
+ vpc.delete
75
+ end
18
76
  end
19
77
 
20
- action :delete do
21
- if existing_vpc
22
- converge_by "Deleting VPC #{fqn} in #{new_driver.aws_config.region}" do
23
- existing_vpc.delete
78
+ private
79
+
80
+ def update_vpc_attributes(vpc)
81
+ # Figure out what (if anything) we need to update
82
+ update_attributes = {}
83
+ %w(enable_dns_support enable_dns_hostnames).each do |name|
84
+ desired_value = new_resource.public_send(name)
85
+ if !desired_value.nil?
86
+ # enable_dns_support -> enableDnsSupport
87
+ aws_attr_name = name.gsub(/_./) { |v| v[1..1].upcase }
88
+ name = name.to_sym
89
+ actual_value = vpc.client.describe_vpc_attribute(vpc_id: vpc.id, attribute: aws_attr_name)
90
+ if actual_value[name][:value] != desired_value
91
+ update_attributes[name] = { old_value: actual_value[name][:value], value: desired_value }
92
+ end
24
93
  end
25
94
  end
26
95
 
27
- new_resource.delete
96
+ update_attributes.each do |name, update|
97
+ converge_by "update #{name} to #{update[:value].inspect} (was #{update[:old_value].inspect}) in VPC #{new_resource.name} (#{vpc.id})" do
98
+ vpc.client.modify_vpc_attribute(:vpc_id => vpc.id, name => { value: update[:value] })
99
+ end
100
+ end
28
101
  end
29
102
 
30
- def existing_vpc
31
- @existing_vpc ||= begin
32
- new_driver.ec2.vpcs.with_tag('Name', new_resource.name).first
33
- rescue
34
- nil
103
+ def update_internet_gateway(vpc)
104
+ current_ig = vpc.internet_gateway
105
+ case new_resource.internet_gateway
106
+ when String, Chef::Resource::AwsInternetGateway, AWS::EC2::InternetGateway
107
+ new_ig = Chef::Resource::AwsInternetGateway.get_aws_object(new_resource.internet_gateway, resource: new_resource)
108
+ if !current_ig
109
+ converge_by "attach Internet Gateway #{new_resource.internet_gateway} to VPC #{vpc.id}" do
110
+ new_ig.attach(vpc.id)
111
+ end
112
+ elsif current_ig != new_ig
113
+ converge_by "replace Internet Gateway #{current_ig.id} on VPC #{vpc.id} with new Internet Gateway #{new_ig.id}" do
114
+ current_ig.detach(vpc.id)
115
+ new_ig.attach(vpc.id)
116
+ end
117
+ if current_ig.tags['OwnedByVPC'] == vpc.id
118
+ converge_by "destroy Internet Gateway #{current_ig.id} in #{region} (owned by VPC #{vpc.id})" do
119
+ current_ig.delete
120
+ end
121
+ end
122
+ end
123
+ when true
124
+ if !current_ig
125
+ converge_by "attach new Internet Gateway to VPC #{vpc.id}" do
126
+ current_ig = AWS.ec2(config: vpc.config).internet_gateways.create
127
+ action_handler.report_progress "create Internet Gateway #{current_ig.id}"
128
+ current_ig.tags['OwnedByVPC'] = vpc.id
129
+ action_handler.report_progress "tag Internet Gateway #{current_ig.id} as OwnedByVpc: #{vpc.id}"
130
+ vpc.internet_gateway = current_ig
131
+ end
132
+ end
133
+ when false
134
+ if current_ig
135
+ converge_by "detach Internet Gateway #{current_ig.id} from VPC #{vpc.id}" do
136
+ current_ig.detach(vpc.id)
137
+ end
138
+ if current_ig.tags['OwnedByVPC'] == vpc.id
139
+ converge_by "destroy Internet Gateway #{current_ig.id} in #{region} (owned by VPC #{vpc.id})" do
140
+ current_ig.delete
141
+ end
142
+ end
143
+ end
35
144
  end
36
145
  end
37
146
 
38
- def id
39
- new_resource.vpc_id
147
+ def update_main_route_table(vpc)
148
+ desired_route_table = Chef::Resource::AwsRouteTable.get_aws_object(new_resource.main_route_table, resource: new_resource)
149
+ current_route_table = vpc.route_tables.main_route_table
150
+ if current_route_table != desired_route_table
151
+ main_association = current_route_table.associations.select { |a| a.main? }.first
152
+ if !main_association
153
+ raise "No main route table association found for VPC #{new_resource.name} (#{vpc.id})'s current main route table #{current_route_table.id}: error! Probably a race condition."
154
+ end
155
+ converge_by "change main route table for VPC #{new_resource.name} (#{vpc.id}) to #{desired_route_table.id} (was #{current_route_table.id})" do
156
+ vpc.client.replace_route_table_association(
157
+ association_id: main_association.id,
158
+ route_table_id: desired_route_table.id)
159
+ end
160
+ end
161
+ desired_route_table
40
162
  end
41
163
 
164
+ def update_main_routes(vpc, main_route_table)
165
+ main_route_table ||= vpc.route_tables.main_route_table
166
+ aws_route_table main_route_table do
167
+ vpc vpc
168
+ routes new_resource.main_routes
169
+ end
170
+ main_route_table
171
+ end
172
+
173
+ def update_dhcp_options(vpc)
174
+ dhcp_options = vpc.dhcp_options
175
+ desired_dhcp_options = Chef::Resource::AwsDhcpOptions.get_aws_object(new_resource.dhcp_options, resource: new_resource)
176
+ if dhcp_options != desired_dhcp_options
177
+ converge_by "change DHCP options for VPC #{new_resource.name} (#{vpc.id}) to #{new_resource.dhcp_options} (#{desired_dhcp_options.id}) - was #{dhcp_options.id}" do
178
+ vpc.dhcp_options = desired_dhcp_options
179
+ end
180
+ end
181
+ end
42
182
  end