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.
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