chef-provisioning-aws 1.9.0 → 1.10.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 (31) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +6 -4
  3. data/lib/chef/provider/aws_auto_scaling_group.rb +15 -1
  4. data/lib/chef/provider/aws_cloudwatch_alarm.rb +84 -0
  5. data/lib/chef/provider/aws_ebs_volume.rb +1 -1
  6. data/lib/chef/provider/aws_image.rb +13 -5
  7. data/lib/chef/provider/aws_launch_configuration.rb +4 -4
  8. data/lib/chef/provider/aws_nat_gateway.rb +57 -0
  9. data/lib/chef/provider/aws_network_interface.rb +1 -1
  10. data/lib/chef/provider/aws_route_table.rb +7 -3
  11. data/lib/chef/provider/aws_vpc.rb +20 -0
  12. data/lib/chef/provisioning/aws_driver.rb +2 -0
  13. data/lib/chef/provisioning/aws_driver/aws_provider.rb +1 -1
  14. data/lib/chef/provisioning/aws_driver/driver.rb +10 -5
  15. data/lib/chef/provisioning/aws_driver/tagging_strategy/auto_scaling.rb +76 -0
  16. data/lib/chef/provisioning/aws_driver/version.rb +1 -1
  17. data/lib/chef/resource/aws_auto_scaling_group.rb +12 -8
  18. data/lib/chef/resource/aws_cloudwatch_alarm.rb +35 -0
  19. data/lib/chef/resource/aws_image.rb +4 -4
  20. data/lib/chef/resource/aws_launch_configuration.rb +1 -1
  21. data/lib/chef/resource/aws_nat_gateway.rb +98 -0
  22. data/lib/chef/resource/aws_route_table.rb +1 -0
  23. data/spec/aws_support.rb +1 -1
  24. data/spec/integration/aws_auto_scaling_group_spec.rb +118 -0
  25. data/spec/integration/aws_cloudwatch_alarm_spec.rb +286 -0
  26. data/spec/integration/aws_nat_gateway_spec.rb +52 -0
  27. data/spec/integration/aws_rds_instance_spec.rb +10 -10
  28. data/spec/integration/aws_route_table_spec.rb +22 -0
  29. data/spec/integration/aws_vpc_spec.rb +31 -3
  30. data/spec/spec_helper.rb +4 -2
  31. metadata +11 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5474ba34beb9fa261bd2c3abbe9561772bd36877
4
- data.tar.gz: 602d8d0ce78d094d41e0982e97ddd42654528777
3
+ metadata.gz: a6942ab3aca17cfa681e5023c373ceca03447728
4
+ data.tar.gz: 937b97d44672eb3c4aa85e2730211b09f03d218e
5
5
  SHA512:
6
- metadata.gz: e410f83858985cc03647c57e074aafd8ad8ec7d9db663c0ed02c477823a33b70f06a7152b815c47298a35fbb8ef319565686fa7cade07db53100d4aea164322f
7
- data.tar.gz: d42f36a75e6644ffc964e6cfc794e8cab50ca7622553e9310669d2630a5e5478a674581adcaadbf3f0e3003e5487efaa7b1a2a559ae03d2c73ef1438a34e3da0
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 bootstrap_options: {
395
- subnet_id: 'my_subnet',
396
- security_group_ids: ['my_sg']
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( new_resource.name, options )
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 < TimeoutError
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 "delete image #{new_resource} in #{region}" do
25
- image.delete
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.ec2.instances[instance_id]
30
+ instance = new_resource.driver.ec2_resource.instance(instance_id)
31
31
  converge_by "waiting until instance #{instance.id} is :terminated" do
32
- wait_for_status(instance, :terminated, [AWS::EC2::Errors::InvalidInstanceID::NotFound, AWS::Core::Resource::NotFound])
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
- image = Chef::Resource::AwsImage.get_aws_object_id(new_resource.image, resource: new_resource)
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
- image,
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
- image = Chef::Resource::AwsImage.get_aws_object_id(new_resource.image, resource: new_resource)
27
- if image != launch_configuration.image_id
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 < TimeoutError
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 < TimeoutError
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
- actual_image = ec2.images.create(image_options.to_hash)
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.id,
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