chef-provisioning-aws 1.4.1 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +8 -0
  3. data/README.md +26 -39
  4. data/Rakefile +13 -5
  5. data/lib/chef/provider/aws_iam_instance_profile.rb +60 -0
  6. data/lib/chef/provider/aws_iam_role.rb +98 -0
  7. data/lib/chef/provider/aws_image.rb +1 -1
  8. data/lib/chef/provider/aws_internet_gateway.rb +75 -0
  9. data/lib/chef/provider/aws_route_table.rb +3 -2
  10. data/lib/chef/provider/aws_s3_bucket.rb +4 -1
  11. data/lib/chef/provider/aws_security_group.rb +1 -1
  12. data/lib/chef/provider/aws_vpc.rb +50 -45
  13. data/lib/chef/provisioning/aws_driver.rb +22 -1
  14. data/lib/chef/provisioning/aws_driver/aws_provider.rb +13 -5
  15. data/lib/chef/provisioning/aws_driver/aws_resource.rb +173 -165
  16. data/lib/chef/provisioning/aws_driver/credentials.rb +12 -0
  17. data/lib/chef/provisioning/aws_driver/driver.rb +82 -37
  18. data/lib/chef/provisioning/aws_driver/super_lwrp.rb +56 -43
  19. data/lib/chef/provisioning/aws_driver/version.rb +1 -1
  20. data/lib/chef/resource/aws_dhcp_options.rb +1 -1
  21. data/lib/chef/resource/aws_ebs_volume.rb +1 -1
  22. data/lib/chef/resource/aws_eip_address.rb +1 -1
  23. data/lib/chef/resource/aws_iam_instance_profile.rb +33 -0
  24. data/lib/chef/resource/aws_iam_role.rb +55 -0
  25. data/lib/chef/resource/aws_image.rb +1 -1
  26. data/lib/chef/resource/aws_instance.rb +1 -1
  27. data/lib/chef/resource/aws_internet_gateway.rb +36 -6
  28. data/lib/chef/resource/aws_load_balancer.rb +1 -1
  29. data/lib/chef/resource/aws_network_acl.rb +1 -1
  30. data/lib/chef/resource/aws_network_interface.rb +1 -1
  31. data/lib/chef/resource/aws_route53_hosted_zone.rb +261 -0
  32. data/lib/chef/resource/aws_route53_record_set.rb +162 -0
  33. data/lib/chef/resource/aws_route_table.rb +1 -1
  34. data/lib/chef/resource/aws_security_group.rb +1 -1
  35. data/lib/chef/resource/aws_sns_topic.rb +1 -1
  36. data/lib/chef/resource/aws_subnet.rb +1 -1
  37. data/lib/chef/resource/aws_vpc.rb +1 -1
  38. data/lib/chef/resource/aws_vpc_peering_connection.rb +1 -1
  39. data/spec/aws_support.rb +11 -13
  40. data/spec/aws_support/matchers/create_an_aws_object.rb +7 -1
  41. data/spec/aws_support/matchers/have_aws_object_tags.rb +1 -1
  42. data/spec/aws_support/matchers/match_an_aws_object.rb +7 -1
  43. data/spec/aws_support/matchers/update_an_aws_object.rb +8 -2
  44. data/spec/integration/aws_eip_address_spec.rb +74 -0
  45. data/spec/integration/aws_iam_instance_profile_spec.rb +159 -0
  46. data/spec/integration/aws_iam_role_spec.rb +177 -0
  47. data/spec/integration/aws_internet_gateway_spec.rb +161 -0
  48. data/spec/integration/aws_network_interface_spec.rb +3 -4
  49. data/spec/integration/aws_route53_hosted_zone_spec.rb +522 -0
  50. data/spec/integration/aws_route_table_spec.rb +52 -4
  51. data/spec/integration/aws_s3_bucket_spec.rb +1 -1
  52. data/spec/integration/load_balancer_spec.rb +303 -8
  53. data/spec/integration/machine_batch_spec.rb +1 -0
  54. data/spec/integration/machine_image_spec.rb +32 -17
  55. data/spec/integration/machine_spec.rb +11 -29
  56. data/spec/unit/chef/provisioning/aws_driver/driver_spec.rb +0 -1
  57. data/spec/unit/chef/provisioning/aws_driver/route53_spec.rb +105 -0
  58. metadata +48 -6
@@ -87,6 +87,15 @@ module AWSDriver
87
87
  end
88
88
  end
89
89
 
90
+ def load_env_variables
91
+ if ENV["AWS_ACCESS_KEY_ID"] && ENV["AWS_SECRET_ACCESS_KEY"]
92
+ @credentials["default"] = {
93
+ aws_access_key_id: ENV["AWS_ACCESS_KEY_ID"],
94
+ aws_secret_access_key: ENV["AWS_SECRET_ACCESS_KEY"]
95
+ }
96
+ end
97
+ end
98
+
90
99
  def load_default
91
100
  config_file = ENV['AWS_CONFIG_FILE'] || File.expand_path('~/.aws/config')
92
101
  credentials_file = ENV['AWS_CREDENTIAL_FILE'] || File.expand_path('~/.aws/credentials')
@@ -97,6 +106,9 @@ module AWSDriver
97
106
  load_inis(config_file)
98
107
  end
99
108
  end
109
+ if @credentials.size == 0
110
+ load_env_variables
111
+ end
100
112
  end
101
113
 
102
114
  def self.method_missing(name, *args, &block)
@@ -28,7 +28,13 @@ require 'base64'
28
28
 
29
29
  # loads the entire aws-sdk
30
30
  AWS.eager_autoload!
31
- AWS_V2_SERVICES = {"EC2" => "ec2", "S3" => "s3", "ElasticLoadBalancing" => "elb", "IAM" => "iam"}
31
+ AWS_V2_SERVICES = {
32
+ "EC2" => "ec2",
33
+ "Route53" => "route53",
34
+ "S3" => "s3",
35
+ "ElasticLoadBalancing" => "elb",
36
+ "IAM" => "iam",
37
+ }
32
38
  Aws.eager_autoload!(:services => AWS_V2_SERVICES.keys)
33
39
 
34
40
  # Need to load the resources after the SDK because `aws_sdk_types` can mess
@@ -53,6 +59,24 @@ class Resource
53
59
  end
54
60
  end
55
61
 
62
+ require 'chef/provider/load_balancer'
63
+ class Chef
64
+ class Provider
65
+ class LoadBalancer
66
+ # We override this so we can specify a machine name as `i-123456`
67
+ # This is totally a hack until we move away from base resources
68
+ def get_machine_spec!(machine_name)
69
+ if machine_name =~ /^i-[a-f0-9]{8}$/
70
+ Struct.new(:name, :reference).new(machine_name, {'instance_id' => machine_name})
71
+ else
72
+ Chef::Log.debug "Getting machine spec for #{machine_name}"
73
+ Provisioning.chef_managed_entry_store(new_resource.chef_server).get!(:machine, machine_name)
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
79
+
56
80
  Chef::Provider::Machine.additional_machine_option_keys << :aws_tags
57
81
  Chef::Provider::MachineImage.additional_image_option_keys << :aws_tags
58
82
  Chef::Provider::LoadBalancer.additional_lb_option_keys << :aws_tags
@@ -66,7 +90,7 @@ module AWSDriver
66
90
  include Chef::Mixin::ShellOut
67
91
  include Chef::Mixin::DeepMerge
68
92
 
69
- attr_reader :aws_config
93
+ attr_reader :aws_config, :aws_config_2
70
94
 
71
95
  # URL scheme:
72
96
  # aws:profilename:region
@@ -97,7 +121,7 @@ module AWSDriver
97
121
  # Right now we are supporting both V1 and V2, so we create 2 config sets
98
122
  credentials2 = Credentials2.new(:profile_name => profile_name)
99
123
  Chef::Config.chef_provisioning ||= {}
100
- ::Aws.config.update(
124
+ @aws_config_2 = {
101
125
  credentials: credentials2.get_credentials,
102
126
  region: region || ENV["AWS_DEFAULT_REGION"] || credentials[:region],
103
127
  # TODO when we get rid of V1 replace the credentials class with something that knows how
@@ -105,7 +129,27 @@ module AWSDriver
105
129
  :http_proxy => credentials[:proxy_uri] || nil,
106
130
  logger: Chef::Log.logger,
107
131
  retry_limit: Chef::Config.chef_provisioning[:aws_retry_limit] || 5
108
- )
132
+ }
133
+
134
+ driver = self
135
+ Chef::Resource::Machine.send(:define_method, :aws_object) do
136
+ resource = Chef::Resource::AwsInstance.new(name, nil)
137
+ resource.driver driver
138
+ resource.managed_entry_store Chef::Provisioning.chef_managed_entry_store
139
+ resource.aws_object
140
+ end
141
+ Chef::Resource::MachineImage.send(:define_method, :aws_object) do
142
+ resource = Chef::Resource::AwsImage.new(name, nil)
143
+ resource.driver driver
144
+ resource.managed_entry_store Chef::Provisioning.chef_managed_entry_store
145
+ resource.aws_object
146
+ end
147
+ Chef::Resource::LoadBalancer.send(:define_method, :aws_object) do
148
+ resource = Chef::Resource::AwsLoadBalancer.new(name, nil)
149
+ resource.driver driver
150
+ resource.managed_entry_store Chef::Provisioning.chef_managed_entry_store
151
+ resource.aws_object
152
+ end
109
153
  end
110
154
 
111
155
  def self.canonicalize_url(driver_url, config)
@@ -141,7 +185,10 @@ module AWSDriver
141
185
  updates << " with tags #{lb_options[:aws_tags]}" if lb_options[:aws_tags]
142
186
 
143
187
  action_handler.perform_action updates do
144
- actual_elb = elb.load_balancers.create(lb_spec.name, lb_options)
188
+ # IAM says the server certificate exists, but ELB throws this error
189
+ Chef::Provisioning::AWSDriver::AWSProvider.retry_with_backoff(AWS::ELB::Errors::CertificateNotFound) do
190
+ actual_elb = elb.load_balancers.create(lb_spec.name, lb_options)
191
+ end
145
192
 
146
193
  lb_spec.reference = {
147
194
  'driver_version' => Chef::Provisioning::AWSDriver::VERSION,
@@ -157,22 +204,9 @@ module AWSDriver
157
204
  end
158
205
 
159
206
  # TODO: refactor this whole giant method into many smaller method calls
160
- # TODO if we update scheme, we don't need to run any of the other updates.
161
- # Also, if things aren't specified (such as machines / listeners), we
162
- # need to grab them from the actual load balancer so we don't lose them.
163
- # i.e. load_balancer 'blah' do
164
- # lb_options: { scheme: 'other_scheme' }
165
- # end
166
- # TODO we will leak the actual_elb if we fail to finish creating it
167
- # Update scheme - scheme is immutable once set, so if it is changing we need to delete the old
168
- # ELB and create a new one
169
207
  if lb_options[:scheme] && lb_options[:scheme].downcase != actual_elb.scheme
170
- desc = [" updating scheme to #{lb_options[:scheme]}"]
171
- desc << " WARN: scheme is immutable, so deleting and re-creating the ELB"
172
- perform_action.call(desc) do
173
- old_elb = actual_elb
174
- actual_elb = elb.load_balancers.create(lb_spec.name, lb_options)
175
- end
208
+ # TODO CloudFormation automatically recreates the load_balancer, we should too
209
+ raise "Scheme is immutable - you need to :destroy and :create the load_balancer to recreated it with the new scheme"
176
210
  end
177
211
 
178
212
  # Update security groups
@@ -248,12 +282,13 @@ module AWSDriver
248
282
  load_balancer_name: actual_elb.name,
249
283
  subnets: attach_subnets
250
284
  )
251
- rescue AWS::ELB::Errors::InvalidConfigurationRequest
252
- raise "You cannot currently move from 1 subnet to another in the same availability zone. " +
285
+ rescue AWS::ELB::Errors::InvalidConfigurationRequest => e
286
+ Chef::Log.error "You cannot currently move from 1 subnet to another in the same availability zone. " +
253
287
  "Amazon does not have an atomic operation which allows this. You must create a new " +
254
288
  "ELB with the correct subnets and move instances into it. Tried to attach subets " +
255
289
  "#{attach_subnets.join(', ')} (availability zones #{enable_zones.join(', ')}) to " +
256
290
  "existing ELB named #{actual_elb.name}"
291
+ raise e
257
292
  end
258
293
  end
259
294
  end
@@ -591,11 +626,11 @@ EOD
591
626
  class_eval <<-META
592
627
 
593
628
  def #{short_name}_client
594
- @#{short_name}_client ||= ::Aws::#{load_name}::Client.new
629
+ @#{short_name}_client ||= ::Aws::#{load_name}::Client.new(**aws_config_2)
595
630
  end
596
631
 
597
632
  def #{short_name}_resource
598
- @#{short_name}_resource ||= ::Aws::#{load_name}::Resource.new(#{short_name}_client)
633
+ @#{short_name}_resource ||= ::Aws::#{load_name}::Resource.new(**(aws_config_2.merge({client: #{short_name}_client})))
599
634
  end
600
635
 
601
636
  META
@@ -621,10 +656,6 @@ EOD
621
656
  @s3 ||= AWS::S3.new(config: aws_config)
622
657
  end
623
658
 
624
- def rds
625
- @rds ||= AWS::RDS.new(config: aws_config)
626
- end
627
-
628
659
  def sns
629
660
  @sns ||= AWS::SNS.new(config: aws_config)
630
661
  end
@@ -697,9 +728,6 @@ EOD
697
728
  Chef::Log.debug('No key specified, generating a default one...')
698
729
  bootstrap_options[:key_name] = default_aws_keypair(action_handler, machine_spec)
699
730
  end
700
- if bootstrap_options[:iam_instance_profile] && bootstrap_options[:iam_instance_profile].is_a?(String)
701
- bootstrap_options[:iam_instance_profile] = {name: bootstrap_options[:iam_instance_profile]}
702
- end
703
731
  if bootstrap_options[:user_data]
704
732
  bootstrap_options[:user_data] = Base64.encode64(bootstrap_options[:user_data])
705
733
  end
@@ -727,6 +755,12 @@ EOD
727
755
 
728
756
  bootstrap_options = AWSResource.lookup_options(bootstrap_options, managed_entry_store: machine_spec.managed_entry_store, driver: self)
729
757
 
758
+ # We do this after the lookup_options because we need the aws_iam_instance_profile resource to
759
+ # only be passed a String during resource lookup, not `{name: ...}`
760
+ if bootstrap_options[:iam_instance_profile] && bootstrap_options[:iam_instance_profile].is_a?(String)
761
+ bootstrap_options[:iam_instance_profile] = {name: bootstrap_options[:iam_instance_profile]}
762
+ end
763
+
730
764
  # In the migration from V1 to V2 we still support associate_public_ip_address at the top level
731
765
  # we do this after the lookup because we have to copy any present subnets, etc. into the
732
766
  # network interfaces block
@@ -1007,7 +1041,7 @@ EOD
1007
1041
  image ||= image_for(image_spec)
1008
1042
  time_elapsed = 0
1009
1043
  sleep_time = 10
1010
- max_wait_time = 300
1044
+ max_wait_time = Chef::Config.chef_provisioning[:image_max_wait_time] || 300
1011
1045
  if !yield(image)
1012
1046
  action_handler.report_progress "waiting for #{image_spec.name} (#{image.id} on #{driver_url}) to be ready ..."
1013
1047
  while time_elapsed < max_wait_time && !yield(image)
@@ -1030,8 +1064,7 @@ EOD
1030
1064
 
1031
1065
  def wait_until_machine(action_handler, machine_spec, output_msg, instance=nil, &block)
1032
1066
  instance ||= instance_for(machine_spec)
1033
- # TODO make these configurable from Chef::Config
1034
- max_attempts = 12
1067
+ max_attempts = ((Chef::Config.chef_provisioning[:machine_max_wait_time] || 120) / 10).floor
1035
1068
  delay = 10
1036
1069
  log_progress = Proc.new do |attempts, response|
1037
1070
  action_handler.report_progress "been waiting #{delay*attempts}/#{delay*max_attempts} -- sleeping #{delay} seconds for #{machine_spec.name} (#{instance.id} on #{driver_url}) to #{output_msg} ..."
@@ -1054,7 +1087,7 @@ EOD
1054
1087
  instance = instance_for(machine_spec)
1055
1088
  time_elapsed = 0
1056
1089
  sleep_time = 10
1057
- max_wait_time = 120
1090
+ max_wait_time = Chef::Config.chef_provisioning[:machine_max_wait_time] || 120
1058
1091
  transport = transport_for(machine_spec, machine_options, instance)
1059
1092
  unless transport.available?
1060
1093
  if action_handler.should_perform_actions
@@ -1178,12 +1211,24 @@ EOD
1178
1211
  end
1179
1212
 
1180
1213
  def create_instance_and_reference(bootstrap_options, action_handler, machine_spec, machine_options)
1181
- instance = ec2_resource.create_instances(bootstrap_options.to_hash)[0]
1214
+ instance = nil
1215
+ # IAM says the instance profile is ready, but EC2 doesn't think it is
1216
+ # Not using retry_with_backoff here because we need to match on a string
1217
+ Retryable.retryable(
1218
+ :tries => 10,
1219
+ :sleep => lambda { |n| [2**n, 16].min },
1220
+ :on => ::Aws::EC2::Errors::InvalidParameterValue,
1221
+ :matching => /Invalid IAM Instance Profile name/
1222
+ ) do |retries, exception|
1223
+ Chef::Log.debug("Instance creation InvalidParameterValue exception is #{exception.inspect}")
1224
+ instance = ec2_resource.create_instances(bootstrap_options.to_hash)[0]
1225
+ end
1226
+
1182
1227
  # Make sure the instance is ready to be tagged
1183
1228
  instance.wait_until_exists
1184
1229
 
1185
1230
  # Sometimes tagging fails even though the instance 'exists'
1186
- Retryable.retryable(:tries => 12, :sleep => 5, :on => [::Aws::EC2::Errors::InvalidInstanceIDNotFound]) do
1231
+ Chef::Provisioning::AWSDriver::AWSProvider.retry_with_backoff(::Aws::EC2::Errors::InvalidInstanceIDNotFound) do
1187
1232
  instance.create_tags({tags: [{key: "Name", value: machine_spec.name}]})
1188
1233
  end
1189
1234
  if machine_options.has_key?(:source_dest_check)
@@ -5,60 +5,73 @@ module Provisioning
5
5
  module AWSDriver
6
6
  class SuperLWRP < Chef::Resource::LWRPBase
7
7
  #
8
- # Add the :lazy_default and :coerce validation_opts to `attribute`
8
+ # Add the :default lazy { ... } and :coerce validation_opts to `attribute`
9
9
  #
10
- def self.attribute(attr_name, validation_opts={})
11
- lazy_default = validation_opts.delete(:lazy_default)
12
- coerce = validation_opts.delete(:coerce)
13
- if lazy_default || coerce
14
- define_method(attr_name) do |arg=nil|
15
- arg = instance_exec(arg, &coerce) if coerce && !arg.nil?
10
+ if self.respond_to?(:properties)
11
+ # in Chef 12.5+, properties replace attributes and these respond to
12
+ # coerce and default with a lazy block - no need for overwriting!
13
+ else
14
+ def self.attribute(attr_name, validation_opts={})
15
+ if validation_opts[:default].is_a?(Chef::DelayedEvaluator)
16
+ lazy_default = validation_opts.delete(:default)
17
+ end
18
+ coerce = validation_opts.delete(:coerce)
19
+ if lazy_default || coerce
20
+ define_method(attr_name) do |arg=nil|
21
+ arg = instance_exec(arg, &coerce) if coerce && !arg.nil?
16
22
 
17
- result = set_or_return(attr_name.to_sym, arg, validation_opts)
23
+ result = set_or_return(attr_name.to_sym, arg, validation_opts)
18
24
 
19
- if result.nil? && arg.nil?
20
- result = instance_eval(&lazy_default) if lazy_default
21
- end
25
+ if result.nil? && arg.nil?
26
+ result = instance_eval(&lazy_default) if lazy_default
27
+ end
22
28
 
23
- result
24
- end
25
- define_method(:"#{attr_name}=") do |arg|
26
- if arg.nil?
27
- remove_instance_variable(:"@#{arg}")
28
- else
29
- set_or_return(attr_name.to_sym, arg, validation_opts)
29
+ result
30
+ end
31
+ define_method(:"#{attr_name}=") do |arg|
32
+ if arg.nil?
33
+ remove_instance_variable(:"@#{arg}")
34
+ else
35
+ set_or_return(attr_name.to_sym, arg, validation_opts)
36
+ end
30
37
  end
38
+ else
39
+ super
31
40
  end
32
- else
33
- super
34
41
  end
35
- end
36
42
 
37
- # FUUUUUU cloning - this works for Chef 11 or 12.1
38
- def load_prior_resource(*args)
39
- Chef::Log.debug "Overloading #{self.resource_name} load_prior_resource with NOOP"
43
+ # Below chef 12.5 you cannot do `default lazy: { ... }` - this adds that
44
+ def self.lazy(&block)
45
+ Chef::DelayedEvaluator.new(&block)
46
+ end
40
47
  end
41
- end
42
- end
43
- end
44
- end
45
48
 
46
- module NoResourceCloning
47
- def prior_resource
48
- if resource_class <= Chef::Provisioning::AWSDriver::SuperLWRP
49
- Chef::Log.debug "Canceling resource cloning for #{resource_class}"
50
- nil
51
- else
52
- super
49
+ # copy from Chef 12.5 params_validate.rb at http://redirx.me/?t35q.
50
+ if !method_defined?(:_pv_is)
51
+ def _pv_is(opts, key, to_be, raise_error: true)
52
+ return true if !opts.has_key?(key.to_s) && !opts.has_key?(key.to_sym)
53
+ value = _pv_opts_lookup(opts, key)
54
+ to_be = [ to_be ].flatten(1)
55
+ to_be.each do |tb|
56
+ case tb
57
+ when Proc
58
+ return true if instance_exec(value, &tb)
59
+ when Property
60
+ validate(opts, { key => tb.validation_options })
61
+ return true
62
+ else
63
+ return true if tb === value
64
+ end
65
+ end
66
+
67
+ if raise_error
68
+ raise ::Chef::Exceptions::ValidationFailed, "Option #{key} must be one of: #{to_be.join(", ")}! You passed #{value.inspect}."
69
+ else
70
+ false
71
+ end
72
+ end
53
73
  end
54
74
  end
55
- def emit_cloned_resource_warning; end
56
- def emit_harmless_cloning_debug; end
57
75
  end
58
-
59
- # Chef 12.2 changed `load_prior_resource` logic to be in the Chef::ResourceBuilder class
60
- # but that class only exists in 12.2 and up
61
- if defined? Chef::ResourceBuilder
62
- # Ruby 2.0.0 has prepend as a protected method
63
- Chef::ResourceBuilder.send(:prepend, NoResourceCloning)
76
+ end
64
77
  end
@@ -1,7 +1,7 @@
1
1
  class Chef
2
2
  module Provisioning
3
3
  module AWSDriver
4
- VERSION = '1.4.1'
4
+ VERSION = '1.5.0'
5
5
  end
6
6
  end
7
7
  end
@@ -47,7 +47,7 @@ class Chef::Resource::AwsDhcpOptions < Chef::Provisioning::AWSDriver::AWSResourc
47
47
  #
48
48
  attribute :netbios_node_type, kind_of: Integer
49
49
 
50
- attribute :dhcp_options_id, kind_of: String, aws_id_attribute: true, lazy_default: proc {
50
+ attribute :dhcp_options_id, kind_of: String, aws_id_attribute: true, default: lazy {
51
51
  name =~ /^dopt-[a-f0-9]{8}$/ ? name : nil
52
52
  }
53
53
 
@@ -19,7 +19,7 @@ class Chef::Resource::AwsEbsVolume < Chef::Provisioning::AWSDriver::AWSResourceW
19
19
  attribute :encrypted, kind_of: [ TrueClass, FalseClass ]
20
20
  attribute :device, kind_of: String
21
21
 
22
- attribute :volume_id, kind_of: String, aws_id_attribute: true, lazy_default: proc {
22
+ attribute :volume_id, kind_of: String, aws_id_attribute: true, default: lazy {
23
23
  name =~ /^vol-[a-f0-9]{8}$/ ? name : nil
24
24
  }
25
25
 
@@ -26,7 +26,7 @@ class Chef::Resource::AwsEipAddress < Chef::Provisioning::AWSDriver::AWSResource
26
26
  # ```
27
27
  #
28
28
  attribute :public_ip, kind_of: String, aws_id_attribute: true, coerce: proc { |v| IPAddr.new(v); v },
29
- lazy_default: proc {
29
+ default: lazy {
30
30
  begin
31
31
  IPAddr.new(name)
32
32
  name
@@ -0,0 +1,33 @@
1
+ require 'chef/provisioning/aws_driver/aws_resource'
2
+
3
+ #
4
+ # An AWS IAM instance profile, a container for an IAM role that you can use to
5
+ # pass role information to an EC2 instance when the instance starts..
6
+ #
7
+ # `name` is unique for an AWS account.
8
+ #
9
+ # API documentation for the AWS Ruby SDK for IAM instance profiles (and the object returned from `aws_object`) can be found here:
10
+ #
11
+ # - http://docs.aws.amazon.com/sdkforruby/api/Aws/IAM/InstanceProfile.html
12
+ #
13
+ class Chef::Resource::AwsIamInstanceProfile < Chef::Provisioning::AWSDriver::AWSResource
14
+ aws_sdk_type ::Aws::IAM::InstanceProfile
15
+
16
+ #
17
+ # The name of the instance profile to create.
18
+ #
19
+ attribute :name, kind_of: String, name_attribute: true
20
+
21
+ #
22
+ # The path to the instance profile. For more information about paths, see http://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html
23
+ #
24
+ attribute :path, kind_of: String
25
+
26
+ attribute :role, kind_of: [ String, AwsIamRole, ::Aws::IAM::Role]
27
+
28
+ def aws_object
29
+ result = driver.iam_resource.instance_profile(name)
30
+ result && result.exists? ? result : nil
31
+ end
32
+
33
+ end