chef-provisioning-aws 0.4.0 → 0.5.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 (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