chef-provisioning-aws 1.3.1 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +70 -69
  3. data/Rakefile +22 -2
  4. data/lib/chef/provider/aws_auto_scaling_group.rb +3 -2
  5. data/lib/chef/provider/aws_cache_cluster.rb +3 -2
  6. data/lib/chef/provider/aws_cache_replication_group.rb +5 -4
  7. data/lib/chef/provider/aws_cache_subnet_group.rb +5 -4
  8. data/lib/chef/provider/aws_cloudsearch_domain.rb +163 -0
  9. data/lib/chef/provider/aws_dhcp_options.rb +9 -6
  10. data/lib/chef/provider/aws_ebs_volume.rb +7 -3
  11. data/lib/chef/provider/aws_eip_address.rb +8 -7
  12. data/lib/chef/provider/aws_image.rb +8 -3
  13. data/lib/chef/provider/aws_instance.rb +14 -2
  14. data/lib/chef/provider/aws_key_pair.rb +2 -1
  15. data/lib/chef/provider/aws_launch_configuration.rb +4 -2
  16. data/lib/chef/provider/aws_load_balancer.rb +18 -0
  17. data/lib/chef/provider/aws_network_acl.rb +6 -2
  18. data/lib/chef/provider/aws_network_interface.rb +11 -24
  19. data/lib/chef/provider/aws_rds_instance.rb +66 -0
  20. data/lib/chef/provider/aws_rds_subnet_group.rb +89 -0
  21. data/lib/chef/provider/aws_route_table.rb +42 -23
  22. data/lib/chef/provider/aws_s3_bucket.rb +32 -8
  23. data/lib/chef/provider/aws_security_group.rb +11 -4
  24. data/lib/chef/provider/aws_server_certificate.rb +23 -0
  25. data/lib/chef/provider/aws_sns_topic.rb +4 -3
  26. data/lib/chef/provider/aws_sqs_queue.rb +3 -2
  27. data/lib/chef/provider/aws_subnet.rb +10 -7
  28. data/lib/chef/provider/aws_vpc.rb +54 -21
  29. data/lib/chef/provider/aws_vpc_peering_connection.rb +88 -0
  30. data/lib/chef/provisioning/aws_driver.rb +8 -0
  31. data/lib/chef/provisioning/aws_driver/aws_provider.rb +45 -76
  32. data/lib/chef/provisioning/aws_driver/aws_rds_resource.rb +11 -0
  33. data/lib/chef/provisioning/aws_driver/aws_resource.rb +14 -2
  34. data/lib/chef/provisioning/aws_driver/aws_resource_with_entry.rb +2 -8
  35. data/lib/chef/provisioning/aws_driver/aws_taggable.rb +18 -0
  36. data/lib/chef/provisioning/aws_driver/aws_tagger.rb +61 -0
  37. data/lib/chef/provisioning/aws_driver/credentials2.rb +51 -0
  38. data/lib/chef/provisioning/aws_driver/driver.rb +214 -162
  39. data/lib/chef/provisioning/aws_driver/tagging_strategy/ec2.rb +64 -0
  40. data/lib/chef/provisioning/aws_driver/tagging_strategy/elb.rb +39 -0
  41. data/lib/chef/provisioning/aws_driver/tagging_strategy/rds.rb +92 -0
  42. data/lib/chef/provisioning/aws_driver/tagging_strategy/s3.rb +41 -0
  43. data/lib/chef/provisioning/aws_driver/version.rb +1 -1
  44. data/lib/chef/resource/aws_cache_cluster.rb +1 -2
  45. data/lib/chef/resource/aws_cloudsearch_domain.rb +46 -0
  46. data/lib/chef/resource/aws_dhcp_options.rb +2 -0
  47. data/lib/chef/resource/aws_ebs_volume.rb +3 -1
  48. data/lib/chef/resource/aws_eip_address.rb +0 -3
  49. data/lib/chef/resource/aws_image.rb +3 -0
  50. data/lib/chef/resource/aws_instance.rb +7 -2
  51. data/lib/chef/resource/aws_internet_gateway.rb +2 -0
  52. data/lib/chef/resource/aws_load_balancer.rb +3 -0
  53. data/lib/chef/resource/aws_network_acl.rb +2 -0
  54. data/lib/chef/resource/aws_network_interface.rb +3 -1
  55. data/lib/chef/resource/aws_rds_instance.rb +42 -0
  56. data/lib/chef/resource/aws_rds_subnet_group.rb +29 -0
  57. data/lib/chef/resource/aws_route_table.rb +7 -5
  58. data/lib/chef/resource/aws_s3_bucket.rb +3 -0
  59. data/lib/chef/resource/aws_security_group.rb +2 -7
  60. data/lib/chef/resource/aws_server_certificate.rb +21 -0
  61. data/lib/chef/resource/aws_subnet.rb +2 -0
  62. data/lib/chef/resource/aws_vpc.rb +4 -1
  63. data/lib/chef/resource/aws_vpc_peering_connection.rb +73 -0
  64. data/spec/acceptance/aws_ebs_volume/nodes/ettores-mbp.lan.json +3 -0
  65. data/spec/aws_support.rb +25 -8
  66. data/spec/aws_support/aws_resource_run_wrapper.rb +5 -1
  67. data/spec/aws_support/deep_matcher/match_values_failure_messages.rb +19 -0
  68. data/spec/aws_support/matchers/create_an_aws_object.rb +1 -1
  69. data/spec/aws_support/matchers/destroy_an_aws_object.rb +1 -1
  70. data/spec/aws_support/matchers/have_aws_object_tags.rb +9 -15
  71. data/spec/aws_support/matchers/match_an_aws_object.rb +1 -1
  72. data/spec/aws_support/matchers/update_an_aws_object.rb +1 -1
  73. data/spec/integration/aws_cloudsearch_domain_spec.rb +31 -0
  74. data/spec/integration/aws_dhcp_options_spec.rb +73 -0
  75. data/spec/integration/aws_ebs_volume_spec.rb +97 -0
  76. data/spec/integration/aws_network_acl_spec.rb +51 -0
  77. data/spec/integration/aws_network_interface_spec.rb +89 -0
  78. data/spec/integration/aws_rds_instance_spec.rb +150 -0
  79. data/spec/integration/aws_rds_subnet_group_spec.rb +105 -0
  80. data/spec/integration/aws_route_table_spec.rb +94 -7
  81. data/spec/integration/aws_s3_bucket_spec.rb +88 -0
  82. data/spec/integration/aws_security_group_spec.rb +47 -0
  83. data/spec/integration/aws_server_certificate_spec.rb +24 -0
  84. data/spec/integration/aws_subnet_spec.rb +51 -2
  85. data/spec/integration/aws_vpc_peering_connection_spec.rb +99 -0
  86. data/spec/integration/aws_vpc_spec.rb +73 -0
  87. data/spec/integration/load_balancer_spec.rb +101 -0
  88. data/spec/integration/machine_image_spec.rb +61 -6
  89. data/spec/integration/machine_spec.rb +26 -0
  90. data/spec/spec_helper.rb +3 -0
  91. data/spec/unit/{aws_driver → chef/provisioning/aws_driver}/credentials_spec.rb +0 -0
  92. data/spec/unit/chef/provisioning/aws_driver/driver_spec.rb +88 -0
  93. metadata +63 -20
  94. data/spec/integration/aws_tagged_items_spec.rb +0 -166
@@ -1,7 +1,10 @@
1
1
  require 'chef/provisioning/aws_driver/aws_provider'
2
- require 'retryable'
3
2
 
4
3
  class Chef::Provider::AwsDhcpOptions < Chef::Provisioning::AWSDriver::AWSProvider
4
+ include Chef::Provisioning::AWSDriver::TaggingStrategy::EC2ConvergeTags
5
+
6
+ provides :aws_dhcp_options
7
+
5
8
  protected
6
9
 
7
10
  def create_aws_object
@@ -10,7 +13,7 @@ class Chef::Provider::AwsDhcpOptions < Chef::Provisioning::AWSDriver::AWSProvide
10
13
  options[:domain_name_servers] = "AmazonProvidedDNS"
11
14
  end
12
15
 
13
- converge_by "create new dhcp_options #{new_resource.name} in #{region}" do
16
+ converge_by "create DHCP options #{new_resource.name} in #{region}" do
14
17
  dhcp_options = new_resource.driver.ec2.dhcp_options.create(options)
15
18
  retry_with_backoff(AWS::EC2::Errors::InvalidDhcpOptionsID::NotFound) do
16
19
  dhcp_options.tags['Name'] = new_resource.name
@@ -35,17 +38,17 @@ class Chef::Provider::AwsDhcpOptions < Chef::Provisioning::AWSDriver::AWSProvide
35
38
  if action_handler.should_perform_actions
36
39
  dhcp_options = AWS.ec2(config: dhcp_options.config).dhcp_options.create(config.merge(desired_options))
37
40
  end
38
- action_handler.report_progress "create new dhcp_options #{dhcp_options.id} with new attributes in #{region}"
41
+ action_handler.report_progress "create DHCP options #{dhcp_options.id} with new attributes in #{region}"
39
42
 
40
43
  # attach dhcp_options to existing vpcs
41
44
  old_dhcp_options.vpcs.each do |vpc|
42
- action_handler.perform_action "attach new dhcp_options #{dhcp_options.id} to vpc #{vpc.id}" do
45
+ action_handler.perform_action "attach DHCP options #{dhcp_options.id} to vpc #{vpc.id}" do
43
46
  vpc.dhcp_options = dhcp_options
44
47
  end
45
48
  end
46
49
 
47
50
  # delete old dhcp_options
48
- action_handler.perform_action "delete old dhcp_options #{old_dhcp_options.id}" do
51
+ action_handler.perform_action "delete DHCP options #{old_dhcp_options.id}" do
49
52
  old_dhcp_options.delete
50
53
  end
51
54
 
@@ -54,7 +57,7 @@ class Chef::Provider::AwsDhcpOptions < Chef::Provisioning::AWSDriver::AWSProvide
54
57
  end
55
58
 
56
59
  def destroy_aws_object(dhcp_options)
57
- converge_by "delete dhcp_options #{new_resource.name} in #{region}" do
60
+ converge_by "delete DHCP options #{new_resource.name} in #{region}" do
58
61
  dhcp_options.delete
59
62
  end
60
63
  end
@@ -4,6 +4,10 @@ require 'date'
4
4
  require 'retryable'
5
5
 
6
6
  class Chef::Provider::AwsEbsVolume < Chef::Provisioning::AWSDriver::AWSProvider
7
+ include Chef::Provisioning::AWSDriver::TaggingStrategy::EC2ConvergeTags
8
+
9
+ provides :aws_ebs_volume
10
+
7
11
  class VolumeNotFoundError < RuntimeError
8
12
  def initialize(new_resource)
9
13
  super("#{new_resource} does not exist!")
@@ -34,7 +38,7 @@ class Chef::Provider::AwsEbsVolume < Chef::Provisioning::AWSDriver::AWSProvider
34
38
 
35
39
  def create_aws_object
36
40
  volume = nil
37
- converge_by "create new #{new_resource} in #{region}" do
41
+ converge_by "create #{new_resource} in #{region}" do
38
42
  volume = new_resource.driver.ec2.volumes.create(initial_options)
39
43
  retry_with_backoff(AWS::EC2::Errors::InvalidVolumeID::NotFound) do
40
44
  volume.tags['Name'] = new_resource.name
@@ -119,12 +123,12 @@ class Chef::Provider::AwsEbsVolume < Chef::Provisioning::AWSDriver::AWSProvider
119
123
  #
120
124
  # If we were told to attach the volume to a machine, do so
121
125
  #
122
- if expected_instance.is_a?(AWS::EC2::Instance)
126
+ if expected_instance.is_a?(AWS::EC2::Instance) || expected_instance.is_a?(::Aws::EC2::Instance)
123
127
  case status
124
128
  when :in_use
125
129
  # We don't want to attempt to reattach to the same instance and device
126
130
  attachment = current_attachment(volume)
127
- if attachment.instance != expected_instance || attachment.device != new_resource.device
131
+ if attachment.instance.id != expected_instance.id || attachment.device != new_resource.device
128
132
  detach(volume)
129
133
  attach(volume)
130
134
  end
@@ -4,6 +4,7 @@ require 'chef/provisioning/machine_spec'
4
4
  require 'cheffish'
5
5
 
6
6
  class Chef::Provider::AwsEipAddress < Chef::Provisioning::AWSDriver::AWSProvider
7
+ provides :aws_eip_address
7
8
 
8
9
  def action_create
9
10
  elastic_ip = super
@@ -16,10 +17,10 @@ class Chef::Provider::AwsEipAddress < Chef::Provisioning::AWSDriver::AWSProvider
16
17
  protected
17
18
 
18
19
  def create_aws_object
19
- converge_by "create new EIP address in #{region}" do
20
+ converge_by "create Elastic IP address in #{region}" do
20
21
  associate_to_vpc = new_resource.associate_to_vpc
21
22
  if associate_to_vpc.nil?
22
- if desired_instance.is_a?(AWS::EC2::Instance)
23
+ if desired_instance.is_a?(AWS::EC2::Instance) || desired_instance.is_a?(::Aws::EC2::Instance)
23
24
  associate_to_vpc = !!desired_instance.vpc_id
24
25
  Chef::Log.debug "Since associate_to_vpc is not specified and instance #{new_resource.machine} (#{desired_instance.id}) and #{associate_to_vpc ? "is" : "is not"} in a VPC, setting associate_to_vpc to #{associate_to_vpc}."
25
26
  end
@@ -39,11 +40,11 @@ class Chef::Provider::AwsEipAddress < Chef::Provisioning::AWSDriver::AWSProvider
39
40
  def destroy_aws_object(elastic_ip)
40
41
  #if it's attached to something in a vpc, disassociate first
41
42
  if elastic_ip.instance_id != nil && elastic_ip.domain == 'vpc'
42
- converge_by "dissociate Elastic IP Address #{new_resource.name} (#{elastic_ip.public_ip}) from #{elastic_ip.instance_id}" do
43
+ converge_by "dissociate Elastic IP address #{new_resource.name} (#{elastic_ip.public_ip}) from #{elastic_ip.instance_id}" do
43
44
  elastic_ip.disassociate
44
45
  end
45
46
  end
46
- converge_by "delete Elastic IP Address #{new_resource.name} (#{elastic_ip.public_ip}) in #{region}" do
47
+ converge_by "delete Elastic IP address #{new_resource.name} (#{elastic_ip.public_ip}) in #{region}" do
47
48
  elastic_ip.delete
48
49
  end
49
50
  end
@@ -65,9 +66,9 @@ class Chef::Provider::AwsEipAddress < Chef::Provisioning::AWSDriver::AWSProvider
65
66
  #
66
67
  # If we were told to associate the IP to a machine, do so
67
68
  #
68
- if desired_instance.is_a?(AWS::EC2::Instance)
69
+ if desired_instance.is_a?(AWS::EC2::Instance) || desired_instance.is_a?(::Aws::EC2::Instance)
69
70
  if desired_instance.id != elastic_ip.instance_id
70
- converge_by "associate Elastic IP Address #{new_resource.name} (#{elastic_ip.public_ip}) with #{new_resource.machine} (#{desired_instance.id})" do
71
+ converge_by "associate Elastic IP address #{new_resource.name} (#{elastic_ip.public_ip}) with #{new_resource.machine} (#{desired_instance.id})" do
71
72
  elastic_ip.associate instance: desired_instance.id
72
73
  end
73
74
  end
@@ -77,7 +78,7 @@ class Chef::Provider::AwsEipAddress < Chef::Provisioning::AWSDriver::AWSProvider
77
78
  #
78
79
  else
79
80
  if elastic_ip.associated?
80
- converge_by "disassociate Elastic IP Address #{new_resource.name} (#{elastic_ip.public_ip}) from #{elastic_ip.instance_id} in #{region}" do
81
+ converge_by "disassociate Elastic IP address #{new_resource.name} (#{elastic_ip.public_ip}) from #{elastic_ip.instance_id} in #{region}" do
81
82
  aws_object.disassociate
82
83
  end
83
84
  end
@@ -1,13 +1,18 @@
1
1
  require 'chef/provisioning/aws_driver/aws_provider'
2
+ require 'chef/provisioning/aws_driver/tagging_strategy/ec2'
2
3
 
3
4
  class Chef::Provider::AwsImage < Chef::Provisioning::AWSDriver::AWSProvider
5
+ include Chef::Provisioning::AWSDriver::TaggingStrategy::EC2ConvergeTags
6
+
7
+ provides :aws_image
8
+
4
9
  def destroy_aws_object(image)
5
- instance_id = image.tags['From-Instance']
6
- Chef::Log.debug("Found From-Instance tag [#{instance_id}] on #{image.id}")
10
+ instance_id = image.tags['from-instance']
11
+ Chef::Log.debug("Found from-instance tag [#{instance_id}] on #{image.id}")
7
12
  unless instance_id
8
13
  # This is an old image and doesn't have the tag added - lets try and find it from the block device mapping
9
14
  image.block_device_mappings.map do |dev, opts|
10
- snapshot = ec2.snapshots[opts[:snapshot_id]]
15
+ snapshot = new_resource.driver.ec2.snapshots[opts[:snapshot_id]]
11
16
  desc = snapshot.description
12
17
  m = /CreateImage\(([^\)]+)\)/.match(desc)
13
18
  if m
@@ -1,6 +1,11 @@
1
1
  require 'chef/provisioning/aws_driver/aws_provider'
2
+ require 'chef/provisioning/aws_driver/tagging_strategy/ec2'
2
3
 
3
4
  class Chef::Provider::AwsInstance < Chef::Provisioning::AWSDriver::AWSProvider
5
+ include Chef::Provisioning::AWSDriver::TaggingStrategy::EC2ConvergeTags
6
+
7
+ provides :aws_instance
8
+
4
9
  def create_aws_object(instance); end
5
10
 
6
11
  def update_aws_object(instance); end
@@ -10,12 +15,19 @@ class Chef::Provider::AwsInstance < Chef::Provisioning::AWSDriver::AWSProvider
10
15
  message += " in VPC #{instance.vpc.id}" unless instance.vpc.nil?
11
16
  message += " in #{region}"
12
17
  converge_by message do
13
- instance.delete
18
+ instance.terminate
14
19
  end
15
20
  converge_by "waited until instance #{new_resource} is :terminated" do
16
21
  # When purging, we must wait until the instance is fully terminated - thats the only way
17
22
  # to delete the network interface that I can see
18
- wait_for_status(instance, :terminated, [AWS::EC2::Errors::InvalidInstanceID::NotFound])
23
+ instance.wait_until_terminated do |w|
24
+ # TODO look at `wait_for_status` - delay and max_attempts should be configurable
25
+ w.delay = 5
26
+ w.max_attempts = 60
27
+ w.before_wait do |attempts, response|
28
+ action_handler.report_progress "waited #{(attempts-1)*5}/#{60*5}s for #{instance.id} status to terminate..."
29
+ end
30
+ end
19
31
  end
20
32
  end
21
33
  end
@@ -4,7 +4,8 @@ require 'aws-sdk-v1'
4
4
 
5
5
 
6
6
  class Chef::Provider::AwsKeyPair < Chef::Provisioning::AWSDriver::AWSProvider
7
-
7
+ provides :aws_key_pair
8
+
8
9
  action :create do
9
10
  create_key(:create)
10
11
  end
@@ -2,6 +2,8 @@ require 'chef/provisioning/aws_driver/aws_provider'
2
2
  require 'chef/resource/aws_image'
3
3
 
4
4
  class Chef::Provider::AwsLaunchConfiguration < Chef::Provisioning::AWSDriver::AWSProvider
5
+ provides :aws_launch_configuration
6
+
5
7
  protected
6
8
 
7
9
  def create_aws_object
@@ -9,7 +11,7 @@ class Chef::Provider::AwsLaunchConfiguration < Chef::Provisioning::AWSDriver::AW
9
11
  instance_type = new_resource.instance_type || new_resource.driver.default_instance_type
10
12
  options = AWSResource.lookup_options(new_resource.options || options, resource: new_resource)
11
13
 
12
- converge_by "Creating new Launch Configuration #{new_resource.name} in #{region}" do
14
+ converge_by "create launch configuration #{new_resource.name} in #{region}" do
13
15
  new_resource.driver.auto_scaling.launch_configurations.create(
14
16
  new_resource.name,
15
17
  image,
@@ -35,7 +37,7 @@ class Chef::Provider::AwsLaunchConfiguration < Chef::Provisioning::AWSDriver::AW
35
37
  end
36
38
 
37
39
  def destroy_aws_object(launch_configuration)
38
- converge_by "delete Launch Configuration #{new_resource.name} in #{region}" do
40
+ converge_by "delete launch configuration #{new_resource.name} in #{region}" do
39
41
  # TODO add a timeout here.
40
42
  # TODO is InUse really a status guaranteed to go away??
41
43
  begin
@@ -1,6 +1,24 @@
1
1
  require 'chef/provisioning/aws_driver/aws_provider'
2
2
 
3
3
  class Chef::Provider::AwsLoadBalancer < Chef::Provisioning::AWSDriver::AWSProvider
4
+
5
+ def aws_tagger
6
+ @aws_tagger ||= begin
7
+ elb_strategy = Chef::Provisioning::AWSDriver::TaggingStrategy::ELB.new(
8
+ new_resource.driver.elb_client,
9
+ new_resource.name,
10
+ new_resource.aws_tags
11
+ )
12
+ Chef::Provisioning::AWSDriver::AWSTagger.new(elb_strategy, action_handler)
13
+ end
14
+ end
15
+
16
+ def converge_tags
17
+ aws_tagger.converge_tags
18
+ end
19
+
20
+ provides :aws_load_balancer
21
+
4
22
  def destroy_aws_object(load_balancer)
5
23
  converge_by "delete load balancer #{new_resource.name} (#{load_balancer.name}) in #{region}" do
6
24
  load_balancer.delete
@@ -3,6 +3,10 @@ require 'chef/resource/aws_vpc'
3
3
  require 'retryable'
4
4
 
5
5
  class Chef::Provider::AwsNetworkAcl < Chef::Provisioning::AWSDriver::AWSProvider
6
+ include Chef::Provisioning::AWSDriver::TaggingStrategy::EC2ConvergeTags
7
+
8
+ provides :aws_network_acl
9
+
6
10
  def action_create
7
11
  network_acl = super
8
12
 
@@ -12,7 +16,7 @@ class Chef::Provider::AwsNetworkAcl < Chef::Provisioning::AWSDriver::AWSProvider
12
16
  protected
13
17
 
14
18
  def create_aws_object
15
- converge_by "create new Network ACL #{new_resource.name} in #{region}" do
19
+ converge_by "create network ACL #{new_resource.name} in #{region}" do
16
20
  options = {}
17
21
  options[:vpc] = new_resource.vpc if new_resource.vpc
18
22
  options = AWSResource.lookup_options(options, resource: new_resource)
@@ -87,7 +91,7 @@ class Chef::Provider::AwsNetworkAcl < Chef::Provisioning::AWSDriver::AWSProvider
87
91
  end
88
92
 
89
93
  unless replace_rules.empty? && desired_rules.empty? && current_rules.empty?
90
- action_handler.report_progress "update Network ACL #{new_resource.name} #{direction.to_s} rules"
94
+ action_handler.report_progress "update network ACL #{new_resource.name} #{direction.to_s} rules"
91
95
  replace_rules(network_acl, replace_rules)
92
96
  add_rules(network_acl, desired_rules)
93
97
  remove_rules(network_acl, current_rules)
@@ -4,11 +4,9 @@ require 'date'
4
4
  require 'retryable'
5
5
 
6
6
  class Chef::Provider::AwsNetworkInterface < Chef::Provisioning::AWSDriver::AWSProvider
7
- class NetworkInterfaceStatusTimeoutError < TimeoutError
8
- def initialize(new_resource, initial_status, expected_status)
9
- super("timed out waiting for #{new_resource} status to change from #{initial_status} to #{expected_status}!")
10
- end
11
- end
7
+ include Chef::Provisioning::AWSDriver::TaggingStrategy::EC2ConvergeTags
8
+
9
+ provides :aws_network_interface
12
10
 
13
11
  class NetworkInterfaceStatusTimeoutError < TimeoutError
14
12
  def initialize(new_resource, initial_status, expected_status)
@@ -43,7 +41,7 @@ class Chef::Provider::AwsNetworkInterface < Chef::Provisioning::AWSDriver::AWSPr
43
41
  end
44
42
 
45
43
  converge_by "wait for new #{new_resource} in #{region} to become available" do
46
- wait_for_eni_status(eni, :available)
44
+ wait_for_status(eni, :available)
47
45
  eni
48
46
  end
49
47
  end
@@ -122,14 +120,14 @@ class Chef::Provider::AwsNetworkInterface < Chef::Provisioning::AWSDriver::AWSPr
122
120
  #
123
121
  # If we were told to attach the network interface to a machine, do so
124
122
  #
125
- if expected_instance.is_a?(AWS::EC2::Instance)
123
+ if expected_instance.is_a?(AWS::EC2::Instance) || expected_instance.is_a?(::Aws::EC2::Instance)
126
124
  case status
127
125
  when :available
128
126
  attach(eni)
129
127
  when :in_use
130
128
  # We don't want to attempt to reattach to the same instance or device index
131
129
  attachment = current_attachment(eni)
132
- if attachment.instance != expected_instance || (options[:device_index] && attachment.device_index != new_resource.device_index)
130
+ if attachment.instance.id != expected_instance.id || (options[:device_index] && attachment.device_index != new_resource.device_index)
133
131
  detach(eni)
134
132
  attach(eni)
135
133
  end
@@ -153,38 +151,27 @@ class Chef::Provider::AwsNetworkInterface < Chef::Provisioning::AWSDriver::AWSPr
153
151
  eni
154
152
  end
155
153
 
156
- def wait_for_eni_status(eni, expected_status)
157
- initial_status = eni.status
158
- log_callback = proc {
159
- Chef::Log.info("waiting for #{new_resource} status to change to #{expected_status}...")
160
- }
161
-
162
- Retryable.retryable(:tries => 30, :sleep => 2, :on => NetworkInterfaceStatusTimeoutError, :ensure => log_callback) do
163
- raise NetworkInterfaceStatusTimeoutError.new(new_resource, initial_status, expected_status) if eni.status != expected_status
164
- end
165
- end
166
-
167
154
  def detach(eni)
168
155
  attachment = current_attachment(eni)
169
156
  instance = attachment.instance
170
157
 
171
- converge_by "detach #{new_resource} from #{instance.instance_id}" do
158
+ converge_by "detach #{new_resource} from #{instance.id}" do
172
159
  eni.detach
173
160
  end
174
161
 
175
162
  converge_by "wait for #{new_resource} to detach" do
176
- wait_for_eni_status(eni, :available)
163
+ wait_for_status(eni, :available)
177
164
  eni
178
165
  end
179
166
  end
180
167
 
181
168
  def attach(eni)
182
- converge_by "attach #{new_resource} to #{new_resource.machine} (#{expected_instance.instance_id})" do
183
- eni.attach(expected_instance, options)
169
+ converge_by "attach #{new_resource} to #{new_resource.machine} (#{expected_instance.id})" do
170
+ eni.attach(expected_instance.id, options)
184
171
  end
185
172
 
186
173
  converge_by "wait for #{new_resource} to attach" do
187
- wait_for_eni_status(eni, :in_use)
174
+ wait_for_status(eni, :in_use)
188
175
  eni
189
176
  end
190
177
  end
@@ -0,0 +1,66 @@
1
+ require 'chef/provisioning/aws_driver/aws_provider'
2
+ require 'chef/provisioning/aws_driver/tagging_strategy/rds'
3
+
4
+ class Chef::Provider::AwsRdsInstance < Chef::Provisioning::AWSDriver::AWSProvider
5
+ include Chef::Provisioning::AWSDriver::TaggingStrategy::RDSConvergeTags
6
+
7
+ provides :aws_rds_instance
8
+
9
+ REQUIRED_OPTIONS = %i(db_instance_identifier allocated_storage engine
10
+ db_instance_class master_username master_user_password)
11
+
12
+ OTHER_OPTIONS = %i(engine_version multi_az iops publicly_accessible db_name port db_subnet_group_name)
13
+
14
+ def update_aws_object(instance)
15
+ Chef::Log.warn("aws_rds_instance does not support modifying a started instance")
16
+ # There are required optiosn (like `allocated_storage`) that the use may not
17
+ # specify on a resource to perform an update. For example, they may want to
18
+ # only specify iops to modify that attribute on an update after initial
19
+ # creation. In this case we need to load the required options from the existing
20
+ # aws_object and only override it if the user has specified a value in the
21
+ # resource. Ideally, it would be nice to mark values as required on the
22
+ # resource but right now there is not a `required_on_create`. This would
23
+ # also be different if chef-provisioning performed resource cloning, which
24
+ # it does not.
25
+ end
26
+
27
+ def create_aws_object
28
+ converge_by "create RDS instance #{new_resource.db_instance_identifier} in #{region}" do
29
+ new_resource.driver.rds.client.create_db_instance(options_hash)
30
+ end
31
+ end
32
+
33
+ def destroy_aws_object(instance)
34
+ converge_by "delete RDS instance #{new_resource.db_instance_identifier} in #{region}" do
35
+ instance.delete(skip_final_snapshot: true)
36
+ end
37
+ # Wait up to 10 minutes for the db instance to shutdown
38
+ converge_by "waited until RDS instance #{new_resource.name} was deleted" do
39
+ wait_for(
40
+ aws_object: instance,
41
+ query_method: :exists?,
42
+ expected_responses: [false],
43
+ acceptable_errors: [AWS::RDS::Errors::DBInstanceNotFound],
44
+ tries: 60,
45
+ sleep: 10
46
+ )
47
+ end
48
+ end
49
+
50
+ # Sets the additional options then overrides it with all required options from
51
+ # the resource as well as optional options
52
+ def options_hash
53
+ @options_hash ||= begin
54
+ opts = Hash[new_resource.additional_options.map{|(k,v)| [k.to_sym,v]}]
55
+ REQUIRED_OPTIONS.each do |opt|
56
+ opts[opt] = new_resource.send(opt)
57
+ end
58
+ OTHER_OPTIONS.each do |opt|
59
+ opts[opt] = new_resource.send(opt) if ! new_resource.send(opt).nil?
60
+ end
61
+ AWSResource.lookup_options(opts, resource: new_resource)
62
+ opts
63
+ end
64
+ end
65
+
66
+ end
@@ -0,0 +1,89 @@
1
+ require 'chef/provisioning/aws_driver/aws_provider'
2
+ require 'chef/provisioning/aws_driver/tagging_strategy/rds'
3
+
4
+ class Chef::Provider::AwsRdsSubnetGroup < Chef::Provisioning::AWSDriver::AWSProvider
5
+ include Chef::Provisioning::AWSDriver::TaggingStrategy::RDSConvergeTags
6
+
7
+ provides :aws_rds_subnet_group
8
+
9
+ def create_aws_object
10
+ converge_by "create RDS subnet group #{new_resource.name} in #{region}" do
11
+ driver.create_db_subnet_group(desired_options)
12
+ end
13
+ end
14
+
15
+ def destroy_aws_object(object)
16
+ converge_by "delete RDS subnet group #{new_resource.name} in #{region}" do
17
+ driver.delete_db_subnet_group(db_subnet_group_name: new_resource.name)
18
+ end
19
+ end
20
+
21
+ def update_aws_object(object)
22
+ updates = required_updates(object)
23
+ if ! updates.empty?
24
+ converge_by updates do
25
+ driver.modify_db_subnet_group(desired_options)
26
+ end
27
+ end
28
+ end
29
+
30
+ def desired_options
31
+ @desired_options ||= begin
32
+ opts = {}
33
+ opts[:db_subnet_group_name] = new_resource.name
34
+ opts[:db_subnet_group_description] = new_resource.description
35
+ opts[:subnet_ids] = new_resource.subnets
36
+ AWSResource.lookup_options(opts, resource: new_resource)
37
+ end
38
+ end
39
+
40
+ # Given an existing object, return an array of update descriptions
41
+ # representing the updates that need to be made.
42
+ #
43
+ # If no updates are needed, an empty array is returned.
44
+ #
45
+ def required_updates(object)
46
+ ret = []
47
+ if desired_options[:db_subnet_group_description] != object[:db_subnet_group_description]
48
+ ret << " set group description to #{desired_options[:db_subnet_group_description]}"
49
+ end
50
+
51
+ if ! xor_array(desired_options[:subnet_ids], subnet_ids(object[:subnets])).empty?
52
+ ret << " set subnets to #{desired_options[:subnet_ids]}"
53
+ end
54
+
55
+ if ! (desired_options[:aws_tags].nil? || desired_options[:aws_tags].empty?)
56
+ # modify_db_subnet_group doesn't support the tags key according to
57
+ # http://docs.aws.amazon.com/AWSRubySDK/latest/AWS/RDS/Client.html#modify_db_subnet_group-instance_method
58
+ Chef::Log.warn "Updating tags for RDS subnet groups is not supported."
59
+ end
60
+
61
+ ret.unshift("update RDS subnet group #{new_resource.name} in #{region}") unless ret.empty?
62
+ ret
63
+ end
64
+
65
+
66
+ private
67
+
68
+ def subnet_ids(subnets)
69
+ subnets.map {|i| i[:subnet_identifier] }
70
+ end
71
+
72
+ def xor_array(a, b)
73
+ (a | b) - (a & b)
74
+ end
75
+
76
+ # To be in line with the other resources. The aws_tags property
77
+ # takes a hash. But we actually need an array.
78
+ def tag_hash_to_array(tag_hash)
79
+ ret = []
80
+ tag_hash.each do |key, value|
81
+ ret << {:key => key, :value => value}
82
+ end
83
+ ret
84
+ end
85
+
86
+ def driver
87
+ new_resource.driver.rds.client
88
+ end
89
+ end