chef-provisioning-aws 1.9.0 → 1.10.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +6 -4
- data/lib/chef/provider/aws_auto_scaling_group.rb +15 -1
- data/lib/chef/provider/aws_cloudwatch_alarm.rb +84 -0
- data/lib/chef/provider/aws_ebs_volume.rb +1 -1
- data/lib/chef/provider/aws_image.rb +13 -5
- data/lib/chef/provider/aws_launch_configuration.rb +4 -4
- data/lib/chef/provider/aws_nat_gateway.rb +57 -0
- data/lib/chef/provider/aws_network_interface.rb +1 -1
- data/lib/chef/provider/aws_route_table.rb +7 -3
- data/lib/chef/provider/aws_vpc.rb +20 -0
- data/lib/chef/provisioning/aws_driver.rb +2 -0
- data/lib/chef/provisioning/aws_driver/aws_provider.rb +1 -1
- data/lib/chef/provisioning/aws_driver/driver.rb +10 -5
- data/lib/chef/provisioning/aws_driver/tagging_strategy/auto_scaling.rb +76 -0
- data/lib/chef/provisioning/aws_driver/version.rb +1 -1
- data/lib/chef/resource/aws_auto_scaling_group.rb +12 -8
- data/lib/chef/resource/aws_cloudwatch_alarm.rb +35 -0
- data/lib/chef/resource/aws_image.rb +4 -4
- data/lib/chef/resource/aws_launch_configuration.rb +1 -1
- data/lib/chef/resource/aws_nat_gateway.rb +98 -0
- data/lib/chef/resource/aws_route_table.rb +1 -0
- data/spec/aws_support.rb +1 -1
- data/spec/integration/aws_auto_scaling_group_spec.rb +118 -0
- data/spec/integration/aws_cloudwatch_alarm_spec.rb +286 -0
- data/spec/integration/aws_nat_gateway_spec.rb +52 -0
- data/spec/integration/aws_rds_instance_spec.rb +10 -10
- data/spec/integration/aws_route_table_spec.rb +22 -0
- data/spec/integration/aws_vpc_spec.rb +31 -3
- data/spec/spec_helper.rb +4 -2
- metadata +11 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a6942ab3aca17cfa681e5023c373ceca03447728
|
4
|
+
data.tar.gz: 937b97d44672eb3c4aa85e2730211b09f03d218e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7a265b44bc28a8f62cc24c2d054cb4d1a9aec99b72c3a7f219f5e07498fb3e4923cdc3ffada912945df7968c5ba7f8a952de12255d764bd7da7abcda6d16467c
|
7
|
+
data.tar.gz: 7bb902bc96c98c8116f033416ad68823f93265396deb41c43ff8cdea6787e88f7bfe9207216c025d2e204d78d89e7c3db329575c145298035f1a6c3d637d055f
|
data/README.md
CHANGED
@@ -391,10 +391,12 @@ aws_subnet 'my_subnet' do
|
|
391
391
|
end
|
392
392
|
|
393
393
|
machine 'my_machine' do
|
394
|
-
machine_options
|
395
|
-
|
396
|
-
|
397
|
-
|
394
|
+
machine_options(
|
395
|
+
bootstrap_options: {
|
396
|
+
subnet_id: 'my_subnet',
|
397
|
+
security_group_ids: ['my_sg']
|
398
|
+
}
|
399
|
+
)
|
398
400
|
end
|
399
401
|
```
|
400
402
|
|
@@ -1,7 +1,10 @@
|
|
1
1
|
require 'chef/provisioning/aws_driver/aws_provider'
|
2
2
|
require 'set'
|
3
|
+
require 'chef/provisioning/aws_driver/tagging_strategy/auto_scaling'
|
3
4
|
|
4
5
|
class Chef::Provider::AwsAutoScalingGroup < Chef::Provisioning::AWSDriver::AWSProvider
|
6
|
+
include Chef::Provisioning::AWSDriver::TaggingStrategy::AutoScalingConvergeTags
|
7
|
+
|
5
8
|
provides :aws_auto_scaling_group
|
6
9
|
|
7
10
|
protected
|
@@ -12,7 +15,18 @@ class Chef::Provider::AwsAutoScalingGroup < Chef::Provisioning::AWSDriver::AWSPr
|
|
12
15
|
options[:min_size] ||= 1
|
13
16
|
options[:max_size] ||= 1
|
14
17
|
|
15
|
-
new_resource.driver.auto_scaling.groups.create(
|
18
|
+
aws_obj = new_resource.driver.auto_scaling.groups.create(
|
19
|
+
new_resource.name, options)
|
20
|
+
|
21
|
+
new_resource.scaling_policies.each do |policy_name, policy|
|
22
|
+
aws_obj.scaling_policies.put(policy_name.to_s, policy)
|
23
|
+
end
|
24
|
+
|
25
|
+
new_resource.notification_configurations.each do |config|
|
26
|
+
aws_obj.notification_configurations.create(config)
|
27
|
+
end
|
28
|
+
|
29
|
+
aws_obj
|
16
30
|
end
|
17
31
|
end
|
18
32
|
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'chef/provisioning/aws_driver/aws_provider'
|
2
|
+
|
3
|
+
class Chef::Provider::AwsCloudwatchAlarm < Chef::Provisioning::AWSDriver::AWSProvider
|
4
|
+
provides :aws_cloudwatch_alarm
|
5
|
+
|
6
|
+
def create_aws_object
|
7
|
+
converge_by "creating cloudwatch alarm #{new_resource.name} in #{region}" do
|
8
|
+
new_resource.driver.cloudwatch_client.put_metric_alarm(desired_options)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def update_aws_object(alarm)
|
13
|
+
if update_required?(alarm)
|
14
|
+
converge_by "updating cloudwatch alarm #{new_resource.name} in #{region}" do
|
15
|
+
new_resource.driver.cloudwatch_client.put_metric_alarm(desired_options)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def destroy_aws_object(alarm)
|
21
|
+
converge_by "destroying cloudwatch alarm #{new_resource.name} in #{region}" do
|
22
|
+
alarm.delete
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def desired_options
|
27
|
+
@desired_options ||= begin
|
28
|
+
# Because an update is a PUT, we must ensure that any properties not specified
|
29
|
+
# on the resource that are already present on the object stay the same
|
30
|
+
aws_object = new_resource.aws_object
|
31
|
+
opts = {alarm_name: new_resource.name}
|
32
|
+
%i(namespace metric_name comparison_operator
|
33
|
+
evaluation_periods period statistic threshold
|
34
|
+
actions_enabled alarm_description unit).each do |opt|
|
35
|
+
if !new_resource.public_send(opt).nil?
|
36
|
+
opts[opt] = new_resource.public_send(opt)
|
37
|
+
elsif aws_object && !aws_object.public_send(opt).nil?
|
38
|
+
opts[opt] = aws_object.public_send(opt)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
if !new_resource.dimensions.nil?
|
42
|
+
opts[:dimensions] = new_resource.dimensions
|
43
|
+
elsif aws_object && !aws_object.dimensions.nil?
|
44
|
+
opts[:dimensions] = aws_object.dimensions.map! {|d| d.to_h}
|
45
|
+
end
|
46
|
+
# Normally we would just use `lookup_options` here but because these parameters
|
47
|
+
# don't necessarily sound like sns topics we manually do it
|
48
|
+
%i{insufficient_data_actions ok_actions alarm_actions}.each do |opt|
|
49
|
+
if !new_resource.public_send(opt).nil?
|
50
|
+
opts[opt] = new_resource.public_send(opt)
|
51
|
+
opts[opt].map! do |action|
|
52
|
+
if action.kind_of?(String) && !(action =~ /^arn:/)
|
53
|
+
aws_object = Chef::Resource::AwsSnsTopic.get_aws_object(action, resource: new_resource)
|
54
|
+
action = aws_object.arn if aws_object
|
55
|
+
end
|
56
|
+
action
|
57
|
+
end
|
58
|
+
elsif aws_object && !aws_object.public_send(opt).nil?
|
59
|
+
opts[opt] = aws_object.public_send(opt)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
opts
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def update_required?(alarm)
|
67
|
+
%i{namespace metric_name comparison_operator
|
68
|
+
evaluation_periods period statistic threshold
|
69
|
+
actions_enabled alarm_description unit}.each do |opt|
|
70
|
+
if alarm.public_send(opt) != desired_options[opt]
|
71
|
+
return true
|
72
|
+
end
|
73
|
+
end
|
74
|
+
unless (Set.new(alarm.dimensions.map {|d| d.to_h}) ^ Set.new(desired_options[:dimensions])).empty?
|
75
|
+
return true
|
76
|
+
end
|
77
|
+
%i(insufficient_data_actions ok_actions alarm_actions).each do |opt|
|
78
|
+
unless (Set.new(alarm.public_send(opt)) ^ Set.new(desired_options[opt])).empty?
|
79
|
+
return true
|
80
|
+
end
|
81
|
+
end
|
82
|
+
return false
|
83
|
+
end
|
84
|
+
end
|
@@ -14,7 +14,7 @@ class Chef::Provider::AwsEbsVolume < Chef::Provisioning::AWSDriver::AWSProvider
|
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
17
|
-
class VolumeStatusTimeoutError <
|
17
|
+
class VolumeStatusTimeoutError < ::Timeout::Error
|
18
18
|
def initialize(new_resource, initial_status, expected_status)
|
19
19
|
super("timed out waiting for #{new_resource} status to change from #{initial_status} to #{expected_status}!")
|
20
20
|
end
|
@@ -7,7 +7,7 @@ class Chef::Provider::AwsImage < Chef::Provisioning::AWSDriver::AWSProvider
|
|
7
7
|
provides :aws_image
|
8
8
|
|
9
9
|
def destroy_aws_object(image)
|
10
|
-
instance_id = image.tags['from-instance']
|
10
|
+
instance_id = image.tags.map {|t| [t.key, t.value] }.to_h['from-instance']
|
11
11
|
Chef::Log.debug("Found from-instance tag [#{instance_id}] on #{image.id}")
|
12
12
|
unless instance_id
|
13
13
|
# This is an old image and doesn't have the tag added - lets try and find it from the block device mapping
|
@@ -21,15 +21,23 @@ class Chef::Provider::AwsImage < Chef::Provisioning::AWSDriver::AWSProvider
|
|
21
21
|
end
|
22
22
|
end
|
23
23
|
end
|
24
|
-
converge_by "
|
25
|
-
image.
|
24
|
+
converge_by "deregister image #{new_resource} in #{region}" do
|
25
|
+
image.deregister
|
26
26
|
end
|
27
27
|
if instance_id
|
28
28
|
# As part of the image creation process, the source instance was automatically
|
29
29
|
# destroyed - we just need to make sure that has completed successfully
|
30
|
-
instance = new_resource.driver.
|
30
|
+
instance = new_resource.driver.ec2_resource.instance(instance_id)
|
31
31
|
converge_by "waiting until instance #{instance.id} is :terminated" do
|
32
|
-
|
32
|
+
if instance.exists?
|
33
|
+
instance.wait_until_terminated do |w|
|
34
|
+
w.delay = 5
|
35
|
+
w.max_attempts = 60
|
36
|
+
w.before_wait do |attempts, response|
|
37
|
+
action_handler.report_progress "waited #{(attempts-1)*5}/#{60*5}s for #{instance.id} status to terminate..."
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
33
41
|
end
|
34
42
|
end
|
35
43
|
end
|
@@ -7,14 +7,14 @@ class Chef::Provider::AwsLaunchConfiguration < Chef::Provisioning::AWSDriver::AW
|
|
7
7
|
protected
|
8
8
|
|
9
9
|
def create_aws_object
|
10
|
-
|
10
|
+
image_id = Chef::Resource::AwsImage.get_aws_object_id(new_resource.image, resource: new_resource)
|
11
11
|
instance_type = new_resource.instance_type || new_resource.driver.default_instance_type
|
12
12
|
options = AWSResource.lookup_options(new_resource.options || options, resource: new_resource)
|
13
13
|
|
14
14
|
converge_by "create launch configuration #{new_resource.name} in #{region}" do
|
15
15
|
new_resource.driver.auto_scaling.launch_configurations.create(
|
16
16
|
new_resource.name,
|
17
|
-
|
17
|
+
image_id,
|
18
18
|
instance_type,
|
19
19
|
options
|
20
20
|
)
|
@@ -23,8 +23,8 @@ class Chef::Provider::AwsLaunchConfiguration < Chef::Provisioning::AWSDriver::AW
|
|
23
23
|
|
24
24
|
def update_aws_object(launch_configuration)
|
25
25
|
if new_resource.image
|
26
|
-
|
27
|
-
if
|
26
|
+
image_id = Chef::Resource::AwsImage.get_aws_object_id(new_resource.image, resource: new_resource)
|
27
|
+
if image_id != launch_configuration.image_id
|
28
28
|
raise "#{new_resource.to_s}.image = #{new_resource.image} (#{image.id}), but actual launch configuration has image set to #{launch_configuration.image_id}. Cannot be modified!"
|
29
29
|
end
|
30
30
|
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
#require 'chef/provisioning/aws_driver/aws_provider'
|
2
|
+
require 'retryable'
|
3
|
+
|
4
|
+
class Chef::Provider::AwsNatGateway < Chef::Provisioning::AWSDriver::AWSProvider
|
5
|
+
|
6
|
+
provides :aws_nat_gateway
|
7
|
+
|
8
|
+
protected
|
9
|
+
|
10
|
+
def create_aws_object
|
11
|
+
if new_resource.subnet.nil?
|
12
|
+
raise "Nat Gateway create action for '#{new_resource.name}' requires the 'subnet' attribute."
|
13
|
+
end
|
14
|
+
subnet = Chef::Resource::AwsSubnet.get_aws_object(new_resource.subnet, resource: new_resource)
|
15
|
+
|
16
|
+
if new_resource.eip_address.nil?
|
17
|
+
# TODO Ideally it would be nice to automatically manage an eip address but
|
18
|
+
# the lack of tagging support and the limited SDK interaction with these two
|
19
|
+
# resources makes that too hard right now. So we force the user to manage their
|
20
|
+
# eip address as a seperate resource.
|
21
|
+
raise "Nat Gateway create action for '#{new_resource.name}' requires the 'eip_address' attribute."
|
22
|
+
end
|
23
|
+
eip_address = Chef::Resource::AwsEipAddress.get_aws_object(new_resource.eip_address, resource: new_resource)
|
24
|
+
|
25
|
+
converge_by "create nat gateway #{new_resource.name} in region #{region} for subnet #{subnet}" do
|
26
|
+
options = {
|
27
|
+
subnet_id: subnet.id,
|
28
|
+
allocation_id: eip_address.allocation_id
|
29
|
+
}
|
30
|
+
|
31
|
+
nat_gateway = new_resource.driver.ec2_resource.create_nat_gateway(options)
|
32
|
+
wait_for_state(nat_gateway, ['available'])
|
33
|
+
nat_gateway
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def update_aws_object(nat_gateway)
|
38
|
+
subnet_id = Chef::Resource::AwsSubnet.get_aws_object_id(new_resource.subnet, resource: new_resource) if new_resource.subnet
|
39
|
+
if subnet_id != nat_gateway.subnet_id
|
40
|
+
raise "Nat gateway subnet cannot be changed after being created! Desired subnet for #{new_resource.name} (#{nat_gateway.id}) was \"#{nat_gateway.subnet_id}\" and actual description is \"#{subnet_id}\""
|
41
|
+
end
|
42
|
+
|
43
|
+
if new_resource.eip_address
|
44
|
+
eip_address = Chef::Resource::AwsEipAddress.get_aws_object(new_resource.eip_address, resource: new_resource)
|
45
|
+
if eip_address.nil? or eip_address.allocation_id != nat_gateway.nat_gateway_addresses.first.allocation_id
|
46
|
+
raise "Nat gateway elastic ip address cannot be changed after being created! Desired elastic ip address for #{new_resource.name} (#{nat_gateway.id}) was \"#{nat_gateway.nat_gateway_addresses.first.allocation_id}\" and actual description is \"#{eip_address.allocation_id}\""
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def destroy_aws_object(nat_gateway)
|
52
|
+
converge_by "delete nat gateway #{new_resource.name} in region #{region} for subnet #{nat_gateway.subnet_id}" do
|
53
|
+
nat_gateway.delete
|
54
|
+
wait_for_state(nat_gateway, ['deleted'])
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -8,7 +8,7 @@ class Chef::Provider::AwsNetworkInterface < Chef::Provisioning::AWSDriver::AWSPr
|
|
8
8
|
|
9
9
|
provides :aws_network_interface
|
10
10
|
|
11
|
-
class NetworkInterfaceStatusTimeoutError <
|
11
|
+
class NetworkInterfaceStatusTimeoutError < ::Timeout::Error
|
12
12
|
def initialize(new_resource, initial_status, expected_status)
|
13
13
|
super("timed out waiting for #{new_resource} status to change from #{initial_status} to #{expected_status}!")
|
14
14
|
end
|
@@ -72,7 +72,7 @@ class Chef::Provider::AwsRouteTable < Chef::Provisioning::AWSDriver::AWSProvider
|
|
72
72
|
current_routes = {}
|
73
73
|
route_table.routes.each do |route|
|
74
74
|
# Ignore the automatic local route
|
75
|
-
route_target = route.gateway_id || route.instance_id || route.network_interface_id || route.vpc_peering_connection_id
|
75
|
+
route_target = route.gateway_id || route.nat_gateway_id || route.instance_id || route.network_interface_id || route.vpc_peering_connection_id
|
76
76
|
next if route_target == 'local'
|
77
77
|
next if ignore_route_targets.find { |target| route_target.match(/#{target}/) }
|
78
78
|
current_routes[route.destination_cidr_block] = route
|
@@ -85,7 +85,7 @@ class Chef::Provider::AwsRouteTable < Chef::Provisioning::AWSDriver::AWSProvider
|
|
85
85
|
# If we already have a route to that CIDR block, replace it.
|
86
86
|
if current_routes[destination_cidr_block]
|
87
87
|
current_route = current_routes.delete(destination_cidr_block)
|
88
|
-
current_target = current_route.gateway_id || current_route.instance_id || current_route.network_interface_id || current_route.vpc_peering_connection_id
|
88
|
+
current_target = current_route.gateway_id || current_route.nat_gateway_id || current_route.instance_id || current_route.network_interface_id || current_route.vpc_peering_connection_id
|
89
89
|
if current_target != target
|
90
90
|
action_handler.perform_action "reroute #{destination_cidr_block} to #{route_target} (#{target}) instead of #{current_target}" do
|
91
91
|
current_route.replace(options)
|
@@ -100,7 +100,7 @@ class Chef::Provider::AwsRouteTable < Chef::Provisioning::AWSDriver::AWSProvider
|
|
100
100
|
|
101
101
|
# Delete anything that's left (that wasn't replaced)
|
102
102
|
current_routes.values.each do |current_route|
|
103
|
-
current_target = current_route.gateway_id || current_route.instance_id || current_route.network_interface_id || current_route.vpc_peering_connection_id
|
103
|
+
current_target = current_route.gateway_id || current_route.nat_gateway_id || current_route.instance_id || current_route.network_interface_id || current_route.vpc_peering_connection_id
|
104
104
|
action_handler.perform_action "remove route sending #{current_route.destination_cidr_block} to #{current_target}" do
|
105
105
|
current_route.delete
|
106
106
|
end
|
@@ -140,6 +140,8 @@ class Chef::Provider::AwsRouteTable < Chef::Provisioning::AWSDriver::AWSProvider
|
|
140
140
|
end
|
141
141
|
when /^igw-[A-Fa-f0-9]{8}$/, Chef::Resource::AwsInternetGateway, AWS::EC2::InternetGateway
|
142
142
|
route_target = { internet_gateway: route_target }
|
143
|
+
when /^nat-[A-Fa-f0-9]{17}$/, Chef::Resource::AwsNatGateway, Aws::EC2::NatGateway
|
144
|
+
route_target = { nat_gateway: route_target }
|
143
145
|
when /^eni-[A-Fa-f0-9]{8}$/, Chef::Resource::AwsNetworkInterface, AWS::EC2::NetworkInterface
|
144
146
|
route_target = { network_interface: route_target }
|
145
147
|
when /^pcx-[A-Fa-f0-9]{8}$/, Chef::Resource::AwsVpcPeeringConnection, ::Aws::EC2::VpcPeeringConnection
|
@@ -169,6 +171,8 @@ class Chef::Provider::AwsRouteTable < Chef::Provisioning::AWSDriver::AWSProvider
|
|
169
171
|
updated_route_target[:network_interface_id] = Chef::Resource::AwsNetworkInterface.get_aws_object_id(value, resource: new_resource)
|
170
172
|
when :internet_gateway
|
171
173
|
updated_route_target[:gateway_id] = Chef::Resource::AwsInternetGateway.get_aws_object_id(value, resource: new_resource)
|
174
|
+
when :nat_gateway
|
175
|
+
updated_route_target[:nat_gateway_id] = Chef::Resource::AwsNatGateway.get_aws_object_id(value, resource: new_resource)
|
172
176
|
when :vpc_peering_connection
|
173
177
|
updated_route_target[:vpc_peering_connection_id] = Chef::Resource::AwsVpcPeeringConnection.get_aws_object_id(value, resource: new_resource)
|
174
178
|
when :virtual_private_gateway
|
@@ -68,6 +68,26 @@ class Chef::Provider::AwsVpc < Chef::Provisioning::AWSDriver::AWSProvider
|
|
68
68
|
current_driver = self.new_resource.driver
|
69
69
|
current_chef_server = self.new_resource.chef_server
|
70
70
|
if purging
|
71
|
+
#SDK V2
|
72
|
+
nat_gateways = new_resource.driver.ec2_client.describe_nat_gateways({
|
73
|
+
:filter => [
|
74
|
+
{ name: 'vpc-id', values: [vpc.id] },
|
75
|
+
{ name: 'state', values: ['available', 'pending'] }
|
76
|
+
]
|
77
|
+
}).nat_gateways
|
78
|
+
|
79
|
+
nat_gateways.each do |nat_gw|
|
80
|
+
nat_gw_resource = new_resource.driver.ec2_resource.nat_gateway(nat_gw.nat_gateway_id)
|
81
|
+
Cheffish.inline_resource(self, action) do
|
82
|
+
aws_nat_gateway nat_gw_resource do
|
83
|
+
action :purge
|
84
|
+
driver current_driver
|
85
|
+
chef_server current_chef_server
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
#SDK V1
|
71
91
|
vpc.subnets.each do |s|
|
72
92
|
Cheffish.inline_resource(self, action) do
|
73
93
|
aws_subnet s do
|
@@ -6,6 +6,7 @@ require "chef/resource/aws_cache_cluster"
|
|
6
6
|
require "chef/resource/aws_cache_replication_group"
|
7
7
|
require "chef/resource/aws_cache_subnet_group"
|
8
8
|
require "chef/resource/aws_cloudsearch_domain"
|
9
|
+
require "chef/resource/aws_cloudwatch_alarm"
|
9
10
|
require "chef/resource/aws_dhcp_options"
|
10
11
|
require "chef/resource/aws_ebs_volume"
|
11
12
|
require "chef/resource/aws_eip_address"
|
@@ -18,6 +19,7 @@ require "chef/resource/aws_internet_gateway"
|
|
18
19
|
require "chef/resource/aws_key_pair"
|
19
20
|
require "chef/resource/aws_launch_configuration"
|
20
21
|
require "chef/resource/aws_load_balancer"
|
22
|
+
require "chef/resource/aws_nat_gateway"
|
21
23
|
require "chef/resource/aws_network_acl"
|
22
24
|
require "chef/resource/aws_network_interface"
|
23
25
|
require "chef/resource/aws_rds_instance"
|
@@ -13,7 +13,7 @@ class AWSProvider < Chef::Provider::LWRPBase
|
|
13
13
|
|
14
14
|
AWSResource = Chef::Provisioning::AWSDriver::AWSResource
|
15
15
|
|
16
|
-
class StatusTimeoutError <
|
16
|
+
class StatusTimeoutError < ::Timeout::Error
|
17
17
|
def initialize(aws_object, initial_status, expected_status)
|
18
18
|
super("timed out waiting for #{aws_object.id} status to change from #{initial_status.inspect} to #{expected_status.inspect}!")
|
19
19
|
end
|
@@ -36,6 +36,8 @@ AWS_V2_SERVICES = {
|
|
36
36
|
"ElasticsearchService" => "elasticsearch",
|
37
37
|
"IAM" => "iam",
|
38
38
|
"RDS" => "rds",
|
39
|
+
"CloudWatch" => "cloudwatch",
|
40
|
+
"AutoScaling" => "auto_scaling"
|
39
41
|
}
|
40
42
|
Aws.eager_autoload!(:services => AWS_V2_SERVICES.keys)
|
41
43
|
|
@@ -536,16 +538,17 @@ module AWSDriver
|
|
536
538
|
image_options = (image_options || {}).to_h.dup
|
537
539
|
machine_options = (machine_options || {}).to_h.dup
|
538
540
|
aws_tags = image_options.delete(:aws_tags) || {}
|
539
|
-
if actual_image.nil? || !actual_image.exists? || actual_image.state == :failed
|
541
|
+
if actual_image.nil? || !actual_image.exists? || actual_image.state.to_sym == :failed
|
540
542
|
action_handler.perform_action "Create image #{image_spec.name} from machine #{machine_spec.name} with options #{image_options.inspect}" do
|
541
543
|
image_options[:name] ||= image_spec.name
|
542
544
|
image_options[:instance_id] ||= machine_spec.reference['instance_id']
|
543
545
|
image_options[:description] ||= "Image #{image_spec.name} created from machine #{machine_spec.name}"
|
544
546
|
Chef::Log.debug "AWS Image options: #{image_options.inspect}"
|
545
|
-
|
547
|
+
image_type = ec2_client.create_image(image_options.to_hash)
|
548
|
+
actual_image = ec2_resource.image(image_type.image_id)
|
546
549
|
image_spec.reference = {
|
547
550
|
'driver_version' => Chef::Provisioning::AWSDriver::VERSION,
|
548
|
-
'image_id' => actual_image.
|
551
|
+
'image_id' => actual_image.image_id,
|
549
552
|
'allocated_at' => Time.now.to_i,
|
550
553
|
'from-instance' => image_options[:instance_id]
|
551
554
|
}
|
@@ -565,7 +568,7 @@ module AWSDriver
|
|
565
568
|
aws_tags = image_options.delete(:aws_tags) || {}
|
566
569
|
aws_tags['from-instance'] = image_spec.reference['from-instance'] if image_spec.reference['from-instance']
|
567
570
|
converge_ec2_tags(actual_image, aws_tags, action_handler)
|
568
|
-
if actual_image.state != :available
|
571
|
+
if actual_image.state.to_sym != :available
|
569
572
|
action_handler.report_progress 'Waiting for image to be ready ...'
|
570
573
|
wait_until_ready_image(action_handler, image_spec, actual_image)
|
571
574
|
end
|
@@ -1242,7 +1245,7 @@ EOD
|
|
1242
1245
|
end
|
1243
1246
|
|
1244
1247
|
def wait_until_ready_image(action_handler, image_spec, image=nil)
|
1245
|
-
wait_until_image(action_handler, image_spec, image) { image.state == :available }
|
1248
|
+
wait_until_image(action_handler, image_spec, image) { |image| image.state.to_sym == :available }
|
1246
1249
|
action_handler.report_progress "Image #{image_spec.name} is now ready"
|
1247
1250
|
end
|
1248
1251
|
|
@@ -1259,6 +1262,8 @@ EOD
|
|
1259
1262
|
:matching => /did not become ready within/
|
1260
1263
|
) do |retries, exception|
|
1261
1264
|
action_handler.report_progress "been waiting #{retries*sleep_time}/#{max_wait_time} -- sleeping #{sleep_time} seconds for #{image_spec.name} (#{image.id} on #{driver_url}) to become ready ..."
|
1265
|
+
# We have to manually reload the instance each loop, otherwise data is stale
|
1266
|
+
image.reload
|
1262
1267
|
unless yield(image)
|
1263
1268
|
raise "Image #{image.id} did not become ready within #{max_wait_time} seconds"
|
1264
1269
|
end
|