chef-provisioning-aws 1.3.1 → 1.4.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.
- checksums.yaml +4 -4
- data/README.md +70 -69
- data/Rakefile +22 -2
- data/lib/chef/provider/aws_auto_scaling_group.rb +3 -2
- data/lib/chef/provider/aws_cache_cluster.rb +3 -2
- data/lib/chef/provider/aws_cache_replication_group.rb +5 -4
- data/lib/chef/provider/aws_cache_subnet_group.rb +5 -4
- data/lib/chef/provider/aws_cloudsearch_domain.rb +163 -0
- data/lib/chef/provider/aws_dhcp_options.rb +9 -6
- data/lib/chef/provider/aws_ebs_volume.rb +7 -3
- data/lib/chef/provider/aws_eip_address.rb +8 -7
- data/lib/chef/provider/aws_image.rb +8 -3
- data/lib/chef/provider/aws_instance.rb +14 -2
- data/lib/chef/provider/aws_key_pair.rb +2 -1
- data/lib/chef/provider/aws_launch_configuration.rb +4 -2
- data/lib/chef/provider/aws_load_balancer.rb +18 -0
- data/lib/chef/provider/aws_network_acl.rb +6 -2
- data/lib/chef/provider/aws_network_interface.rb +11 -24
- data/lib/chef/provider/aws_rds_instance.rb +66 -0
- data/lib/chef/provider/aws_rds_subnet_group.rb +89 -0
- data/lib/chef/provider/aws_route_table.rb +42 -23
- data/lib/chef/provider/aws_s3_bucket.rb +32 -8
- data/lib/chef/provider/aws_security_group.rb +11 -4
- data/lib/chef/provider/aws_server_certificate.rb +23 -0
- data/lib/chef/provider/aws_sns_topic.rb +4 -3
- data/lib/chef/provider/aws_sqs_queue.rb +3 -2
- data/lib/chef/provider/aws_subnet.rb +10 -7
- data/lib/chef/provider/aws_vpc.rb +54 -21
- data/lib/chef/provider/aws_vpc_peering_connection.rb +88 -0
- data/lib/chef/provisioning/aws_driver.rb +8 -0
- data/lib/chef/provisioning/aws_driver/aws_provider.rb +45 -76
- data/lib/chef/provisioning/aws_driver/aws_rds_resource.rb +11 -0
- data/lib/chef/provisioning/aws_driver/aws_resource.rb +14 -2
- data/lib/chef/provisioning/aws_driver/aws_resource_with_entry.rb +2 -8
- data/lib/chef/provisioning/aws_driver/aws_taggable.rb +18 -0
- data/lib/chef/provisioning/aws_driver/aws_tagger.rb +61 -0
- data/lib/chef/provisioning/aws_driver/credentials2.rb +51 -0
- data/lib/chef/provisioning/aws_driver/driver.rb +214 -162
- data/lib/chef/provisioning/aws_driver/tagging_strategy/ec2.rb +64 -0
- data/lib/chef/provisioning/aws_driver/tagging_strategy/elb.rb +39 -0
- data/lib/chef/provisioning/aws_driver/tagging_strategy/rds.rb +92 -0
- data/lib/chef/provisioning/aws_driver/tagging_strategy/s3.rb +41 -0
- data/lib/chef/provisioning/aws_driver/version.rb +1 -1
- data/lib/chef/resource/aws_cache_cluster.rb +1 -2
- data/lib/chef/resource/aws_cloudsearch_domain.rb +46 -0
- data/lib/chef/resource/aws_dhcp_options.rb +2 -0
- data/lib/chef/resource/aws_ebs_volume.rb +3 -1
- data/lib/chef/resource/aws_eip_address.rb +0 -3
- data/lib/chef/resource/aws_image.rb +3 -0
- data/lib/chef/resource/aws_instance.rb +7 -2
- data/lib/chef/resource/aws_internet_gateway.rb +2 -0
- data/lib/chef/resource/aws_load_balancer.rb +3 -0
- data/lib/chef/resource/aws_network_acl.rb +2 -0
- data/lib/chef/resource/aws_network_interface.rb +3 -1
- data/lib/chef/resource/aws_rds_instance.rb +42 -0
- data/lib/chef/resource/aws_rds_subnet_group.rb +29 -0
- data/lib/chef/resource/aws_route_table.rb +7 -5
- data/lib/chef/resource/aws_s3_bucket.rb +3 -0
- data/lib/chef/resource/aws_security_group.rb +2 -7
- data/lib/chef/resource/aws_server_certificate.rb +21 -0
- data/lib/chef/resource/aws_subnet.rb +2 -0
- data/lib/chef/resource/aws_vpc.rb +4 -1
- data/lib/chef/resource/aws_vpc_peering_connection.rb +73 -0
- data/spec/acceptance/aws_ebs_volume/nodes/ettores-mbp.lan.json +3 -0
- data/spec/aws_support.rb +25 -8
- data/spec/aws_support/aws_resource_run_wrapper.rb +5 -1
- data/spec/aws_support/deep_matcher/match_values_failure_messages.rb +19 -0
- data/spec/aws_support/matchers/create_an_aws_object.rb +1 -1
- data/spec/aws_support/matchers/destroy_an_aws_object.rb +1 -1
- data/spec/aws_support/matchers/have_aws_object_tags.rb +9 -15
- data/spec/aws_support/matchers/match_an_aws_object.rb +1 -1
- data/spec/aws_support/matchers/update_an_aws_object.rb +1 -1
- data/spec/integration/aws_cloudsearch_domain_spec.rb +31 -0
- data/spec/integration/aws_dhcp_options_spec.rb +73 -0
- data/spec/integration/aws_ebs_volume_spec.rb +97 -0
- data/spec/integration/aws_network_acl_spec.rb +51 -0
- data/spec/integration/aws_network_interface_spec.rb +89 -0
- data/spec/integration/aws_rds_instance_spec.rb +150 -0
- data/spec/integration/aws_rds_subnet_group_spec.rb +105 -0
- data/spec/integration/aws_route_table_spec.rb +94 -7
- data/spec/integration/aws_s3_bucket_spec.rb +88 -0
- data/spec/integration/aws_security_group_spec.rb +47 -0
- data/spec/integration/aws_server_certificate_spec.rb +24 -0
- data/spec/integration/aws_subnet_spec.rb +51 -2
- data/spec/integration/aws_vpc_peering_connection_spec.rb +99 -0
- data/spec/integration/aws_vpc_spec.rb +73 -0
- data/spec/integration/load_balancer_spec.rb +101 -0
- data/spec/integration/machine_image_spec.rb +61 -6
- data/spec/integration/machine_spec.rb +26 -0
- data/spec/spec_helper.rb +3 -0
- data/spec/unit/{aws_driver → chef/provisioning/aws_driver}/credentials_spec.rb +0 -0
- data/spec/unit/chef/provisioning/aws_driver/driver_spec.rb +88 -0
- metadata +63 -20
- data/spec/integration/aws_tagged_items_spec.rb +0 -166
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'chef/provisioning/aws_driver/aws_provider'
|
2
|
+
require 'retryable'
|
3
|
+
|
4
|
+
class Chef::Provider::AwsVpcPeeringConnection < Chef::Provisioning::AWSDriver::AWSProvider
|
5
|
+
provides :aws_vpc_peering_connection
|
6
|
+
|
7
|
+
def action_create
|
8
|
+
vpc_peering_connection = super
|
9
|
+
accept_connection(vpc_peering_connection, new_resource)
|
10
|
+
end
|
11
|
+
|
12
|
+
def action_accept
|
13
|
+
existing_vpc_peering_connection = new_resource.aws_object
|
14
|
+
accept_connection(existing_vpc_peering_connection, new_resource)
|
15
|
+
end
|
16
|
+
|
17
|
+
protected
|
18
|
+
|
19
|
+
def create_aws_object
|
20
|
+
if new_resource.vpc.nil?
|
21
|
+
raise "VCP peering connection create action for '#{new_resource.name}' requires the 'vpc' attribute."
|
22
|
+
elsif new_resource.peer_vpc.nil?
|
23
|
+
raise "VCP peering connection create action for '#{new_resource.name}' requires the 'peer_vpc' attribute."
|
24
|
+
end
|
25
|
+
|
26
|
+
options = {}
|
27
|
+
options[:vpc_id] = new_resource.vpc
|
28
|
+
options[:peer_vpc_id] = new_resource.peer_vpc
|
29
|
+
options[:peer_owner_id] = new_resource.peer_owner_id unless new_resource.peer_owner_id.nil?
|
30
|
+
options = AWSResource.lookup_options(options, resource: new_resource)
|
31
|
+
|
32
|
+
ec2_resource = new_resource.driver.ec2_resource
|
33
|
+
vpc = ec2_resource.vpc(options[:vpc_id])
|
34
|
+
|
35
|
+
converge_by "create peering connection #{new_resource.name} in VPC #{new_resource.vpc} (#{vpc.id}) and region #{region}" do
|
36
|
+
vpc_peering_connection = vpc.request_vpc_peering_connection(options)
|
37
|
+
|
38
|
+
retry_with_backoff(::Aws::EC2::Errors::ServiceError) do
|
39
|
+
ec2_resource.create_tags({
|
40
|
+
:resources => [vpc_peering_connection.id],
|
41
|
+
:tags => [
|
42
|
+
{
|
43
|
+
:key => "Name",
|
44
|
+
:value => new_resource.name
|
45
|
+
}
|
46
|
+
]
|
47
|
+
})
|
48
|
+
end
|
49
|
+
vpc_peering_connection
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def update_aws_object(vpc_peering_connection)
|
54
|
+
vpc_id = vpc_peering_connection.requester_vpc_info.vpc_id
|
55
|
+
peer_vpc_id = vpc_peering_connection.accepter_vpc_info.vpc_id
|
56
|
+
peer_owner_id = vpc_peering_connection.accepter_vpc_info.owner_id
|
57
|
+
|
58
|
+
desired_vpc_id = Chef::Resource::AwsVpc.get_aws_object_id(new_resource.vpc, resource: new_resource)
|
59
|
+
desired_peer_vpc_id = Chef::Resource::AwsVpc.get_aws_object_id(new_resource.peer_vpc, resource: new_resource)
|
60
|
+
desired_peer_owner_id = new_resource.peer_owner_id
|
61
|
+
|
62
|
+
if desired_vpc_id && vpc_id != desired_vpc_id
|
63
|
+
raise "VCP peering connection requester vpc cannot be changed after being created! Desired requester vpc id for #{new_resource.name} (#{vpc_peering_connection.id}) was \"#{desired_vpc_id}\" and actual id is \"#{vpc_id}\""
|
64
|
+
end
|
65
|
+
if desired_peer_vpc_id && peer_vpc_id != desired_peer_vpc_id
|
66
|
+
raise "VCP peering connection accepter vpc cannot be changed after being created! Desired accepter vpc id for #{new_resource.name} (#{vpc_peering_connection.id}) was \"#{desired_peer_vpc_id}\" and actual id is \"#{peer_vpc_id}\""
|
67
|
+
end
|
68
|
+
if desired_peer_owner_id && peer_owner_id != desired_peer_owner_id
|
69
|
+
raise "VCP peering connection accepter owner id vpc cannot be changed after being created! Desired accepter vpc owner id for #{new_resource.name} (#{vpc_peering_connection.id}) was \"#{desired_peer_owner_id}\" and actual owner id is \"#{peer_owner_id}\""
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def destroy_aws_object(vpc_peering_connection)
|
74
|
+
converge_by "delete #{new_resource.to_s} in #{region}" do
|
75
|
+
unless ['deleted', 'failed', 'deleting'].include? vpc_peering_connection.status.code
|
76
|
+
vpc_peering_connection.delete
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
private
|
82
|
+
|
83
|
+
def accept_connection(vpc_peering_connection, new_resource)
|
84
|
+
if new_resource.peer_owner_id.nil? or new_resource.peer_owner_id == new_resource.driver.account_id
|
85
|
+
vpc_peering_connection.accept
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -5,20 +5,28 @@ require "chef/resource/aws_auto_scaling_group"
|
|
5
5
|
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
|
+
require "chef/resource/aws_cloudsearch_domain"
|
8
9
|
require "chef/resource/aws_dhcp_options"
|
9
10
|
require "chef/resource/aws_ebs_volume"
|
10
11
|
require "chef/resource/aws_eip_address"
|
11
12
|
require "chef/resource/aws_image"
|
12
13
|
require "chef/resource/aws_instance"
|
13
14
|
require "chef/resource/aws_internet_gateway"
|
15
|
+
require "chef/resource/aws_key_pair"
|
14
16
|
require "chef/resource/aws_launch_configuration"
|
15
17
|
require "chef/resource/aws_load_balancer"
|
16
18
|
require "chef/resource/aws_network_acl"
|
17
19
|
require "chef/resource/aws_network_interface"
|
18
20
|
require "chef/resource/aws_route_table"
|
21
|
+
require "chef/resource/aws_rds_instance"
|
22
|
+
require "chef/resource/aws_rds_subnet_group"
|
23
|
+
require "chef/resource/aws_route_table"
|
19
24
|
require "chef/resource/aws_s3_bucket"
|
20
25
|
require "chef/resource/aws_security_group"
|
26
|
+
require "chef/resource/aws_server_certificate"
|
21
27
|
require "chef/resource/aws_sns_topic"
|
22
28
|
require "chef/resource/aws_sqs_queue"
|
23
29
|
require "chef/resource/aws_subnet"
|
24
30
|
require "chef/resource/aws_vpc"
|
31
|
+
require "chef/resource/aws_vpc_peering_connection"
|
32
|
+
|
@@ -3,6 +3,8 @@ require 'chef/provisioning/aws_driver/aws_resource'
|
|
3
3
|
require 'chef/provisioning/aws_driver/aws_resource_with_entry'
|
4
4
|
require 'chef/provisioning/chef_managed_entry_store'
|
5
5
|
require 'chef/provisioning/chef_provider_action_handler'
|
6
|
+
# Enough providers will require this that we put it in here
|
7
|
+
require 'chef/provisioning/aws_driver/tagging_strategy/ec2'
|
6
8
|
require 'retryable'
|
7
9
|
|
8
10
|
module Chef::Provisioning::AWSDriver
|
@@ -121,8 +123,6 @@ class AWSProvider < Chef::Provider::LWRPBase
|
|
121
123
|
aws_object = create_aws_object
|
122
124
|
end
|
123
125
|
|
124
|
-
converge_tags(aws_object)
|
125
|
-
|
126
126
|
#
|
127
127
|
# Associate the managed entry with the AWS object
|
128
128
|
#
|
@@ -130,6 +130,12 @@ class AWSProvider < Chef::Provider::LWRPBase
|
|
130
130
|
new_resource.save_managed_entry(aws_object, action_handler, existing_entry: entry)
|
131
131
|
end
|
132
132
|
|
133
|
+
# This has to be after the managed entry save so the `aws_object` lookup
|
134
|
+
# from the resource succeeds
|
135
|
+
if respond_to?(:converge_tags)
|
136
|
+
converge_tags
|
137
|
+
end
|
138
|
+
|
133
139
|
aws_object
|
134
140
|
end
|
135
141
|
|
@@ -223,90 +229,53 @@ class AWSProvider < Chef::Provider::LWRPBase
|
|
223
229
|
raise NotImplementedError, :destroy_aws_object
|
224
230
|
end
|
225
231
|
|
226
|
-
# Update AWS resource tags
|
227
|
-
#
|
228
|
-
# AWS resources which include the TaggedItem Module
|
229
|
-
# will have an 'aws_tags' attribute available.
|
230
|
-
# The 'aws_tags' Hash will apply all the tags within
|
231
|
-
# the hash, and remove existing tags not included within
|
232
|
-
# the hash. The 'Name' tag will not removed. The 'Name'
|
233
|
-
# tag can still be updated in the hash.
|
234
|
-
#
|
235
|
-
# @param aws_object Aws SDK Object to update tags
|
236
|
-
#
|
237
|
-
def converge_tags(aws_object)
|
238
|
-
return unless new_resource.respond_to?(:aws_tags)
|
239
|
-
desired_tags = new_resource.aws_tags
|
240
|
-
# If aws_tags were not provided we exit
|
241
|
-
if desired_tags.nil?
|
242
|
-
Chef::Log.debug "aws_tags not provided, nothing to converge"
|
243
|
-
return
|
244
|
-
end
|
245
|
-
current_tags = aws_object.tags.to_h
|
246
|
-
# AWS always returns tags as strings, and we don't want to overwrite a
|
247
|
-
# tag-as-string with the same tag-as-symbol
|
248
|
-
desired_tags = Hash[desired_tags.map {|k, v| [k.to_s, v.to_s] }]
|
249
|
-
tags_to_update = desired_tags.reject {|k,v| current_tags[k] == v}
|
250
|
-
tags_to_delete = current_tags.keys - desired_tags.keys
|
251
|
-
# We don't want to delete `Name`, just all other tags
|
252
|
-
tags_to_delete.delete('Name')
|
253
|
-
|
254
|
-
unless tags_to_update.empty?
|
255
|
-
converge_by "applying tags #{tags_to_update}" do
|
256
|
-
aws_object.tags.set(tags_to_update)
|
257
|
-
end
|
258
|
-
end
|
259
|
-
unless tags_to_delete.empty?
|
260
|
-
converge_by "deleting tags #{tags_to_delete.inspect}" do
|
261
|
-
aws_object.tags.delete(*tags_to_delete)
|
262
|
-
end
|
263
|
-
end
|
264
|
-
end
|
265
|
-
|
266
|
-
# Wait until aws_object obtains one of expected_status
|
267
|
-
#
|
268
|
-
# @param aws_object Aws SDK Object to check status on
|
269
|
-
# @param expected_status [Symbol,Array<Symbol>] Final status(s) to look for
|
270
|
-
# @param acceptable_errors [Exception,Array<Exception>] Acceptable errors that are caught and squelched
|
271
|
-
# @param tries [Integer] Number of times to check status
|
272
|
-
# @param sleep [Integer] Time to wait between checking status
|
273
|
-
#
|
274
232
|
def wait_for_status(aws_object, expected_status, acceptable_errors = [], tries=60, sleep=5)
|
275
|
-
|
276
|
-
|
277
|
-
|
233
|
+
wait_for(
|
234
|
+
aws_object: aws_object,
|
235
|
+
query_method: :status,
|
236
|
+
expected_responses: expected_status,
|
237
|
+
acceptable_errors: acceptable_errors,
|
238
|
+
tries: tries,
|
239
|
+
sleep: sleep
|
240
|
+
)
|
241
|
+
end
|
278
242
|
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
end
|
243
|
+
def wait_for_state(aws_object, expected_states, acceptable_errors = [], tries=60, sleep=5)
|
244
|
+
wait_for(
|
245
|
+
aws_object: aws_object,
|
246
|
+
query_method: :state,
|
247
|
+
expected_responses: expected_states,
|
248
|
+
acceptable_errors: acceptable_errors,
|
249
|
+
tries: tries,
|
250
|
+
sleep: sleep
|
251
|
+
)
|
289
252
|
end
|
290
253
|
|
291
|
-
# Wait until aws_object obtains one of
|
254
|
+
# Wait until aws_object obtains one of expected_responses
|
292
255
|
#
|
293
256
|
# @param aws_object Aws SDK Object to check state on
|
294
|
-
# @param
|
257
|
+
# @param query_method Method to call on aws_object to get current state
|
258
|
+
# @param expected_responses [Symbol,Array<Symbol>] Final state(s) to look for
|
295
259
|
# @param acceptable_errors [Exception,Array<Exception>] Acceptable errors that are caught and squelched
|
296
|
-
# @param tries [Integer] Number of times to check state
|
297
|
-
# @param sleep [Integer] Time to wait between checking states
|
260
|
+
# @param tries [Integer] Number of times to check state, defaults to 60
|
261
|
+
# @param sleep [Integer] Time to wait between checking states, defaults to 5
|
298
262
|
#
|
299
|
-
def
|
300
|
-
|
301
|
-
|
302
|
-
|
263
|
+
def wait_for(opts={})
|
264
|
+
aws_object = opts[:aws_object]
|
265
|
+
query_method = opts[:query_method]
|
266
|
+
expected_responses = [opts[:expected_responses]].flatten
|
267
|
+
acceptable_errors = [opts[:acceptable_errors] || []].flatten
|
268
|
+
tries = opts[:tries] || 60
|
269
|
+
sleep = opts[:sleep] || 5
|
303
270
|
|
304
271
|
Retryable.retryable(:tries => tries, :sleep => sleep) do |retries, exception|
|
305
|
-
action_handler.report_progress "waited #{retries*sleep}/#{tries*sleep}s for #{aws_object.id} state to change to #{
|
272
|
+
action_handler.report_progress "waited #{retries*sleep}/#{tries*sleep}s for #{aws_object.id} state to change to #{expected_responses.inspect}..."
|
273
|
+
Chef::Log.debug("Current exception is #{exception.inspect}")
|
306
274
|
begin
|
307
|
-
|
308
|
-
|
309
|
-
|
275
|
+
current_response = aws_object.send(query_method)
|
276
|
+
Chef::Log.debug("Current response from [#{query_method}] is #{current_response}")
|
277
|
+
unless expected_responses.include?(current_response)
|
278
|
+
raise StatusTimeoutError.new(aws_object, current_response, expected_responses)
|
310
279
|
end
|
311
280
|
rescue *acceptable_errors
|
312
281
|
end
|
@@ -317,7 +286,7 @@ class AWSProvider < Chef::Provider::LWRPBase
|
|
317
286
|
# @param retry_on [Exception] An exception to retry on, defaults to RuntimeError
|
318
287
|
#
|
319
288
|
def retry_with_backoff(retry_on = RuntimeError, &block)
|
320
|
-
Retryable.retryable(:tries => 10, :sleep => lambda { |n| [2**n,
|
289
|
+
Retryable.retryable(:tries => 10, :sleep => lambda { |n| [2**n, 16].min }, :on => retry_on, &block)
|
321
290
|
end
|
322
291
|
|
323
292
|
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require_relative 'aws_resource'
|
2
|
+
|
3
|
+
module Chef::Provisioning::AWSDriver
|
4
|
+
class AWSRDSResource < AWSResource
|
5
|
+
|
6
|
+
def rds_tagging_type
|
7
|
+
raise "You must add the RDS resource type lookup from http://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_Tagging.html#USER_Tagging.ARN"
|
8
|
+
end
|
9
|
+
|
10
|
+
end
|
11
|
+
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
require 'aws'
|
2
2
|
require 'chef/provisioning/aws_driver/super_lwrp'
|
3
3
|
require 'chef/provisioning/chef_managed_entry_store'
|
4
|
+
# Enough resources will eventually require this that we put 1 require in here
|
5
|
+
require 'chef/provisioning/aws_driver/aws_taggable'
|
4
6
|
|
5
7
|
# Common AWS resource - contains metadata that all AWS resources will need
|
6
8
|
module Chef::Provisioning::AWSDriver
|
@@ -59,12 +61,21 @@ class AWSResource < Chef::Provisioning::AWSDriver::SuperLWRP
|
|
59
61
|
lazy_default: proc { Chef::Provisioning::ChefManagedEntryStore.new(chef_server) }
|
60
62
|
|
61
63
|
#
|
62
|
-
# Get the current AWS object.
|
64
|
+
# Get the current AWS object. This should return the aws_object even if it has
|
65
|
+
# a status like 'deleted' or 'inactive'. If there is an aws_object, we return it.
|
66
|
+
# Callers will need to check the status if they care.
|
63
67
|
#
|
64
68
|
def aws_object
|
65
69
|
raise NotImplementedError, :aws_object
|
66
70
|
end
|
67
71
|
|
72
|
+
def aws_object_id
|
73
|
+
@aws_object_id ||= begin
|
74
|
+
o = aws_object
|
75
|
+
o.public_send(self.class.aws_sdk_class_id) if o
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
68
79
|
#
|
69
80
|
# Look up an AWS options list, translating standard names using the appropriate
|
70
81
|
# classes.
|
@@ -110,6 +121,7 @@ class AWSResource < Chef::Provisioning::AWSDriver::SuperLWRP
|
|
110
121
|
resource.driver driver if driver
|
111
122
|
resource.managed_entry_store managed_entry_store if managed_entry_store
|
112
123
|
end
|
124
|
+
|
113
125
|
result = resource.aws_object
|
114
126
|
if required && result.nil?
|
115
127
|
raise "#{self}[#{value}] does not exist!"
|
@@ -132,7 +144,7 @@ class AWSResource < Chef::Provisioning::AWSDriver::SuperLWRP
|
|
132
144
|
load_provider: true,
|
133
145
|
id: :name,
|
134
146
|
aws_id_prefix: nil)
|
135
|
-
self.resource_name = self.
|
147
|
+
self.resource_name = convert_to_snake_case(self.name.split('::')[-1])
|
136
148
|
@aws_sdk_class = sdk_class
|
137
149
|
@aws_sdk_class_id = id
|
138
150
|
@aws_id_prefix = aws_id_prefix
|
@@ -4,12 +4,6 @@ require 'chef/provisioning/aws_driver/resources'
|
|
4
4
|
# Common AWS resource - contains metadata that all AWS resources will need
|
5
5
|
class Chef::Provisioning::AWSDriver::AWSResourceWithEntry < Chef::Provisioning::AWSDriver::AWSResource
|
6
6
|
|
7
|
-
# This should be a hash of tags to apply to the AWS object
|
8
|
-
#
|
9
|
-
# @param aws_tags [Hash] Should be a hash of keys & values to add. Keys and values
|
10
|
-
# can be provided as symbols or strings, but will be stored in AWS as strings.
|
11
|
-
attribute :aws_tags, kind_of: Hash
|
12
|
-
|
13
7
|
#
|
14
8
|
# Dissociate the ID of this object from Chef.
|
15
9
|
#
|
@@ -19,7 +13,7 @@ class Chef::Provisioning::AWSDriver::AWSResourceWithEntry < Chef::Provisioning::
|
|
19
13
|
#
|
20
14
|
def delete_managed_entry(action_handler)
|
21
15
|
if should_have_managed_entry?
|
22
|
-
managed_entry_store.delete(self.class.
|
16
|
+
managed_entry_store.delete(self.class.managed_entry_type, name, action_handler)
|
23
17
|
end
|
24
18
|
end
|
25
19
|
|
@@ -37,7 +31,7 @@ class Chef::Provisioning::AWSDriver::AWSResourceWithEntry < Chef::Provisioning::
|
|
37
31
|
def save_managed_entry(aws_object, action_handler, existing_entry: nil)
|
38
32
|
if should_have_managed_entry?
|
39
33
|
managed_entry = existing_entry ||
|
40
|
-
managed_entry_store.new_entry(self.class.
|
34
|
+
managed_entry_store.new_entry(self.class.managed_entry_type, name)
|
41
35
|
updated = update_managed_entry(aws_object, managed_entry)
|
42
36
|
if updated || !existing_entry
|
43
37
|
managed_entry.save(action_handler)
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Chef::Provisioning::AWSDriver
|
2
|
+
# This module is meant to be included in a resource that is taggable
|
3
|
+
# This will add the appropriate attribute that can be converged by the provider
|
4
|
+
# TODO it would be nice to not have two seperate modules (taggable/tagger)
|
5
|
+
# and just have the provider decorate the resource or vice versa. Complicated
|
6
|
+
# by resources <-> providers being many-to-many.
|
7
|
+
module AWSTaggable
|
8
|
+
|
9
|
+
def self.included(klass)
|
10
|
+
# This should be a hash of tags to apply to the AWS object
|
11
|
+
#
|
12
|
+
# @param aws_tags [Hash] Should be a hash of keys & values to add. Keys and values
|
13
|
+
# can be provided as symbols or strings, but will be stored in AWS as strings.
|
14
|
+
klass.attribute :aws_tags, kind_of: Hash
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'retryable'
|
2
|
+
|
3
|
+
module Chef::Provisioning::AWSDriver
|
4
|
+
# Include this module on a class or instance that is responsible for tagging
|
5
|
+
# itself. Fill in the hook methods so it knows how to tag itself.
|
6
|
+
class AWSTagger
|
7
|
+
extend Forwardable
|
8
|
+
|
9
|
+
attr_reader :action_handler
|
10
|
+
|
11
|
+
def initialize(tagging_strategy, action_handler)
|
12
|
+
@tagging_strategy = tagging_strategy
|
13
|
+
@action_handler = action_handler
|
14
|
+
end
|
15
|
+
|
16
|
+
def_delegators :@tagging_strategy, :desired_tags, :current_tags, :set_tags, :delete_tags
|
17
|
+
|
18
|
+
def converge_tags
|
19
|
+
if desired_tags.nil?
|
20
|
+
Chef::Log.debug "aws_tags not provided, nothing to converge"
|
21
|
+
return
|
22
|
+
end
|
23
|
+
|
24
|
+
# Duplication and normalization
|
25
|
+
# ::Aws::EC2::Errors::InvalidParameterValue: Tag value cannot be null. Use empty string instead.
|
26
|
+
n_desired_tags = Hash[desired_tags.map {|k,v| [k.to_s, v.to_s]}]
|
27
|
+
n_current_tags = Hash[current_tags.map {|k,v| [k.to_s, v.to_s]}]
|
28
|
+
|
29
|
+
tags_to_set = n_desired_tags.reject {|k,v| n_current_tags[k] && n_current_tags[k] == v}
|
30
|
+
tags_to_delete = n_current_tags.keys - n_desired_tags.keys
|
31
|
+
# We don't want to delete `Name`, just all other tags
|
32
|
+
# Tag keys and values are case sensitive - `Name` is special because it
|
33
|
+
# shows as the name in the console
|
34
|
+
tags_to_delete.delete('Name')
|
35
|
+
|
36
|
+
# Tagging frequently fails so we retry with an exponential backoff, a maximum of 10 seconds
|
37
|
+
Retryable.retryable(
|
38
|
+
:tries => 20,
|
39
|
+
:sleep => lambda { |n| [2**n, 10].min },
|
40
|
+
:on => [AWS::Errors::Base, Aws::Errors::ServiceError,]
|
41
|
+
) do |retries, exception|
|
42
|
+
if retries > 0
|
43
|
+
Chef::Log.info "Retrying the tagging, previous try failed with #{exception.inspect}"
|
44
|
+
end
|
45
|
+
unless tags_to_set.empty?
|
46
|
+
action_handler.perform_action "creating tags #{tags_to_set}" do
|
47
|
+
set_tags(tags_to_set)
|
48
|
+
end
|
49
|
+
tags_to_set = []
|
50
|
+
end
|
51
|
+
unless tags_to_delete.empty?
|
52
|
+
action_handler.perform_action "deleting tags #{tags_to_delete}" do
|
53
|
+
delete_tags(tags_to_delete)
|
54
|
+
end
|
55
|
+
tags_to_delete = []
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|