chef-provisioning-aws 1.6.1 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +37 -0
  3. data/Rakefile +8 -5
  4. data/chef-provisioning-aws.gemspec +3 -3
  5. data/lib/chef/provider/aws_cloudsearch_domain.rb +5 -3
  6. data/lib/chef/provider/aws_elasticsearch_domain.rb +131 -0
  7. data/lib/chef/provider/aws_key_pair.rb +2 -2
  8. data/lib/chef/provider/aws_rds_instance.rb +7 -5
  9. data/lib/chef/provider/aws_rds_subnet_group.rb +7 -7
  10. data/lib/chef/provider/aws_route_table.rb +5 -1
  11. data/lib/chef/provider/aws_server_certificate.rb +4 -3
  12. data/lib/chef/provisioning/aws_driver.rb +1 -0
  13. data/lib/chef/provisioning/aws_driver/aws_provider.rb +2 -1
  14. data/lib/chef/provisioning/aws_driver/driver.rb +109 -38
  15. data/lib/chef/provisioning/aws_driver/tagging_strategy/elasticsearch.rb +40 -0
  16. data/lib/chef/provisioning/aws_driver/version.rb +1 -1
  17. data/lib/chef/resource/aws_eip_address.rb +4 -24
  18. data/lib/chef/resource/aws_elasticsearch_domain.rb +42 -0
  19. data/lib/chef/resource/aws_rds_instance.rb +12 -7
  20. data/lib/chef/resource/aws_route53_hosted_zone.rb +1 -1
  21. data/spec/aws_support.rb +2 -2
  22. data/spec/integration/aws_eip_address_spec.rb +32 -18
  23. data/spec/integration/aws_elasticsearch_domain_spec.rb +119 -0
  24. data/spec/integration/aws_key_pair_spec.rb +2 -1
  25. data/spec/integration/aws_rds_instance_spec.rb +3 -3
  26. data/spec/integration/aws_route53_hosted_zone_spec.rb +11 -0
  27. data/spec/integration/aws_route_table_spec.rb +40 -44
  28. data/spec/integration/aws_server_certificate_spec.rb +12 -0
  29. data/spec/integration/load_balancer_spec.rb +47 -1
  30. data/spec/integration/machine_spec.rb +32 -25
  31. metadata +28 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 62665ba3e28e4e1a98db8822ca277579ae6e3453
4
- data.tar.gz: 20e6faf05a83817c47dccb6d8229d23c006ed25a
3
+ metadata.gz: 1484fb7faef2c0ce2abadef678b520d88219f7de
4
+ data.tar.gz: c7f948fc458daa4f0ba1ba2294f17bf9e368133b
5
5
  SHA512:
6
- metadata.gz: fa274c48c2ec46e0ce297eb55294e7ade6887e461853f7686f3e1dd925310a4b3957d841e65a66a7ed0d0e8bbcedf4ebf249a6442bb0c217fd7d79b660d83391
7
- data.tar.gz: 3c9e658df95add6289bc049ffbd46e652f68ba489c541f1b13aa0106d44fa3b56f63ad957b435b658362e058c9227fddd49653b2075d6f82b957e094f83c2ae4
6
+ metadata.gz: 397a01589702e2d9439a7209dbaaaf3548ca9d5cc7707fd2b2ed05a69dc5f0a9c43fc0524559e4c288e5d76e8180ff6696810fd0e22d9b3c44c80418110d3e9e
7
+ data.tar.gz: 090afbab837aadcf3c502cbc96ec633069cc6685aa67a1c56ae2fc93cc9ace1e8ca725c8735fd7304e9bb991bc887c9d5ab1aced3c869152df4f211ce65508de
data/README.md CHANGED
@@ -187,10 +187,47 @@ load_balancer "my_elb" do
187
187
 
188
188
  The available parameters for `load_balancer_options` can be viewed in the [aws docs](http://docs.aws.amazon.com/AWSRubySDK/latest/AWS/ELB/Client.html#create_load_balancer-instance_method).
189
189
 
190
+ If you wish to enable sticky sessions, pass a `sticky_sessions` key to the
191
+ `load_balancer_options` and specify a cookie name and the ports that should be
192
+ sticky. In the above example, it would look like this:
193
+
194
+ ```ruby
195
+ machine 'test1'
196
+ m2 = machine 'test2'
197
+ load_balancer "my_elb" do
198
+ machines ['test1', m2]
199
+ load_balancer_options({
200
+ subnets: subnets,
201
+ security_groups: [load_balancer_sg],
202
+ listeners: [
203
+ {
204
+ instance_port: 8080,
205
+ protocol: 'HTTP',
206
+ instance_protocol: 'HTTP',
207
+ port: 80
208
+ },
209
+ {
210
+ instance_port: 8080,
211
+ protocol: 'HTTPS',
212
+ instance_protocol: 'HTTP',
213
+ port: 443,
214
+ ssl_certificate_id: "arn:aws:iam::360965486607:server-certificate/cloudfront/foreflight-2015-07-09"
215
+ }
216
+ ],
217
+ sticky_sessions: {
218
+ cookie_name: 'my-app-cookie',
219
+ ports: [80, 443]
220
+ }
221
+ })
222
+ ```
223
+
190
224
  NOTES:
191
225
 
192
226
  1. You can specify either `ssl_certificate_id` or `server_certificate` in a listener but the value to both parameters should be the ARN of an existing IAM::ServerCertificate object.
193
227
 
228
+ 2. The `sticky_sessions` option currently only supports Application-Controlled
229
+ Session Stickiness.
230
+
194
231
  # RDS Instance Options
195
232
 
196
233
  ### Additional Options
data/Rakefile CHANGED
@@ -4,8 +4,6 @@ require 'rspec/core/rake_task'
4
4
 
5
5
  task :default => :spec
6
6
 
7
- ENV['AWS_TEST_DRIVER'] ||= "aws"
8
-
9
7
  desc "run all non-integration specs"
10
8
  RSpec::Core::RakeTask.new(:spec) do |spec|
11
9
  spec.pattern = 'spec/**/*_spec.rb'
@@ -39,9 +37,14 @@ end
39
37
 
40
38
  desc "travis specific task - runs CI integration tests (regular and super_slow in parallel) and sets up travis specific ENV variables"
41
39
  task :travis, [:sub_task] do |t, args|
42
- pattern = "load_balancer_spec.rb,machine_spec.rb,aws_iam_instance_profile_spec.rb,aws_security_group_spec.rb" # This is a comma seperated list
43
- pattern = pattern.split(",").map {|p| "spec/integration/**/*#{p}"}.join(",")
44
- Rake::Task[args[:sub_task]].invoke(pattern)
40
+ sub_task = args[:sub_task]
41
+ if sub_task == "super_slow"
42
+ pattern = "load_balancer_spec.rb,aws_route_table_spec.rb,machine_spec.rb,aws_eip_address_spec.rb" # This is a comma seperated list
43
+ pattern = pattern.split(",").map {|p| "spec/integration/**/*#{p}"}.join(",")
44
+ else
45
+ pattern = 'spec/integration/**/*_spec.rb'
46
+ end
47
+ Rake::Task[sub_task].invoke(pattern)
45
48
  end
46
49
 
47
50
  desc "travis task for machine_image tests - these take so long to run that we only run the first test"
@@ -15,9 +15,9 @@ Gem::Specification.new do |s|
15
15
  s.add_dependency 'chef-provisioning', '~> 1.4'
16
16
 
17
17
  s.add_dependency 'aws-sdk-v1', '>= 1.59.0'
18
- s.add_dependency 'aws-sdk', '~> 2.1'
19
- s.add_dependency 'retryable', '~> 2.0.1'
20
- s.add_dependency 'ubuntu_ami', '~> 0.4.1'
18
+ s.add_dependency 'aws-sdk', ['>= 2.1.26', '< 3.0']
19
+ s.add_dependency 'retryable', '~> 2.0', '>= 2.0.1'
20
+ s.add_dependency 'ubuntu_ami', '~> 0.4', '>= 0.4.1'
21
21
 
22
22
  # chef-zero is only a development dependency because we leverage its RSpec support
23
23
  s.add_development_dependency 'chef-zero', '~> 4.2'
@@ -2,7 +2,7 @@ require 'chef/provisioning/aws_driver/aws_provider'
2
2
 
3
3
  class Chef::Provider::AwsCloudsearchDomain < Chef::Provisioning::AWSDriver::AWSProvider
4
4
  provides :aws_cloudsearch_domain
5
-
5
+
6
6
  def create_aws_object
7
7
  domain = nil # define here to ensure it is available outside of the coverge_by scope
8
8
  converge_by "create CloudSearch domain #{new_resource.name}" do
@@ -127,8 +127,10 @@ class Chef::Provider::AwsCloudsearchDomain < Chef::Provisioning::AWSDriver::AWSP
127
127
  end
128
128
 
129
129
  def create_index_fields
130
- new_resource.index_fields.each do |field|
131
- create_index_field(field)
130
+ unless new_resource.index_fields.nil?
131
+ new_resource.index_fields.each do |field|
132
+ create_index_field(field)
133
+ end
132
134
  end
133
135
  end
134
136
 
@@ -0,0 +1,131 @@
1
+ require 'chef/provisioning/aws_driver/aws_provider'
2
+ require 'chef/provisioning/aws_driver/tagging_strategy/elasticsearch'
3
+
4
+ class Chef::Provider::AwsElasticsearchDomain < Chef::Provisioning::AWSDriver::AWSProvider
5
+ provides :aws_elasticsearch_domain
6
+
7
+ def create_aws_object
8
+ converge_by "create Elasticsearch domain #{new_resource.domain_name}" do
9
+ es_client.create_elasticsearch_domain(update_payload)
10
+ end
11
+ end
12
+
13
+ def destroy_aws_object(domain)
14
+ converge_by "destroy Elasticsearch domain #{new_resource.domain_name}" do
15
+ es_client.delete_elasticsearch_domain({domain_name: new_resource.domain_name})
16
+ end
17
+ end
18
+
19
+ def update_aws_object(domain)
20
+ updates = required_updates(domain)
21
+ if ! updates.empty?
22
+ converge_by updates do
23
+ es_client.update_elasticsearch_domain_config(update_payload)
24
+ end
25
+ end
26
+ end
27
+
28
+ def aws_tagger
29
+ @aws_tagger ||= begin
30
+ strategy = Chef::Provisioning::AWSDriver::TaggingStrategy::Elasticsearch.new(
31
+ es_client,
32
+ new_resource.aws_object.arn,
33
+ new_resource.aws_tags)
34
+ Chef::Provisioning::AWSDriver::AWSTagger.new(strategy, action_handler)
35
+ end
36
+ end
37
+
38
+ def converge_tags
39
+ aws_tagger.converge_tags
40
+ end
41
+
42
+ private
43
+
44
+ def required_updates(object)
45
+ ret = []
46
+ ret << " update cluster configuration" if cluster_options_changed?(object)
47
+ ret << " update ebs options" if ebs_options_changed?(object)
48
+ ret << " update snapshot options" if snapshot_options_changed?(object)
49
+ ret << " update access policy" if access_policy_changed?(object)
50
+ ret.unshift("update Elasticsearch domain #{new_resource.name}") unless ret.empty?
51
+ ret
52
+ end
53
+
54
+ def update_payload
55
+ payload = {domain_name: new_resource.domain_name}
56
+ payload.merge!(ebs_options) if ebs_options_present?
57
+ payload.merge!(cluster_options) if cluster_options_present?
58
+ payload.merge!(snapshot_options) if snapshot_options_present?
59
+ payload[:access_policies] = new_resource.access_policies if new_resource.access_policies
60
+ payload
61
+ end
62
+
63
+ EBS_OPTIONS = %i(ebs_enabled volume_type volume_size iops)
64
+ def ebs_options
65
+ opts = EBS_OPTIONS.inject({}) do |accum, i|
66
+ new_resource.send(i).nil? ? accum : accum.merge({i => new_resource.send(i)})
67
+ end
68
+ {ebs_options: opts}
69
+ end
70
+
71
+ def ebs_options_present?
72
+ EBS_OPTIONS.any? {|i| !new_resource.send(i).nil? }
73
+ end
74
+
75
+ def ebs_options_changed?(object)
76
+ changed?(ebs_options[:ebs_options], object.ebs_options)
77
+ end
78
+
79
+ CLUSTER_OPTIONS = %i(instance_type instance_count dedicated_master_enabled
80
+ dedicated_master_type dedicated_master_count zone_awareness_enabled)
81
+
82
+ def cluster_options
83
+ opts = CLUSTER_OPTIONS.inject({}) do |accum, i|
84
+ new_resource.send(i).nil? ? accum : accum.merge({i => new_resource.send(i)})
85
+ end
86
+ {elasticsearch_cluster_config: opts}
87
+ end
88
+
89
+ def cluster_options_present?
90
+ CLUSTER_OPTIONS.any? {|i| !new_resource.send(i).nil? }
91
+ end
92
+
93
+ def cluster_options_changed?(object)
94
+ changed?(cluster_options[:elasticsearch_cluster_config], object.elasticsearch_cluster_config)
95
+ end
96
+
97
+ def snapshot_options
98
+ if !new_resource.automated_snapshot_start_hour.nil?
99
+ {snapshot_options: { automated_snapshot_start_hour: new_resource.automated_snapshot_start_hour }}
100
+ else
101
+ {}
102
+ end
103
+ end
104
+
105
+ def snapshot_options_present?
106
+ ! new_resource.automated_snapshot_start_hour.nil?
107
+ end
108
+
109
+ def snapshot_options_changed?(object)
110
+ changed?(snapshot_options[:snapshot_options] || {}, object.snapshot_options)
111
+ end
112
+
113
+ def access_policy_changed?(object)
114
+ if new_resource.access_policies
115
+ Chef::JSONCompat.parse(object.access_policies) != Chef::JSONCompat.parse(new_resource.access_policies)
116
+ else
117
+ false
118
+ end
119
+ end
120
+
121
+ def changed?(desired, actual)
122
+ desired.each do |key, value|
123
+ return true if actual[key] != value
124
+ end
125
+ false
126
+ end
127
+
128
+ def es_client
129
+ @es_client ||= new_resource.driver.elasticsearch_client
130
+ end
131
+ end
@@ -5,7 +5,7 @@ require 'aws-sdk-v1'
5
5
 
6
6
  class Chef::Provider::AwsKeyPair < Chef::Provisioning::AWSDriver::AWSProvider
7
7
  provides :aws_key_pair
8
-
8
+
9
9
  action :create do
10
10
  create_key(:create)
11
11
  end
@@ -171,7 +171,7 @@ class Chef::Provider::AwsKeyPair < Chef::Provisioning::AWSDriver::AWSProvider
171
171
  if current_key_pair
172
172
  @current_fingerprint = current_key_pair.fingerprint
173
173
  else
174
- current_resource.action :destroy
174
+ current_resource.action [:destroy]
175
175
  end
176
176
 
177
177
  if new_private_key_path && ::File.exist?(new_private_key_path)
@@ -26,7 +26,7 @@ class Chef::Provider::AwsRdsInstance < Chef::Provisioning::AWSDriver::AWSProvide
26
26
 
27
27
  def create_aws_object
28
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)
29
+ new_resource.driver.rds_resource.create_db_instance(options_hash)
30
30
  end
31
31
  end
32
32
 
@@ -38,12 +38,14 @@ class Chef::Provider::AwsRdsInstance < Chef::Provisioning::AWSDriver::AWSProvide
38
38
  converge_by "waited until RDS instance #{new_resource.name} was deleted" do
39
39
  wait_for(
40
40
  aws_object: instance,
41
- query_method: :exists?,
42
- expected_responses: [false],
43
- acceptable_errors: [AWS::RDS::Errors::DBInstanceNotFound],
41
+ # http://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Overview.DBInstance.Status.html
42
+ # It cannot _actually_ return a deleted status, we're just looking for the error
43
+ query_method: :db_instance_status,
44
+ expected_responses: ['deleted'],
45
+ acceptable_errors: [::Aws::RDS::Errors::DBInstanceNotFound],
44
46
  tries: 60,
45
47
  sleep: 10
46
- )
48
+ ) { |instance| instance.reload }
47
49
  end
48
50
  end
49
51
 
@@ -12,14 +12,14 @@ class Chef::Provider::AwsRdsSubnetGroup < Chef::Provisioning::AWSDriver::AWSProv
12
12
  end
13
13
  end
14
14
 
15
- def destroy_aws_object(object)
15
+ def destroy_aws_object(subnet_group)
16
16
  converge_by "delete RDS subnet group #{new_resource.name} in #{region}" do
17
17
  driver.delete_db_subnet_group(db_subnet_group_name: new_resource.name)
18
18
  end
19
19
  end
20
20
 
21
- def update_aws_object(object)
22
- updates = required_updates(object)
21
+ def update_aws_object(subnet_group)
22
+ updates = required_updates(subnet_group)
23
23
  if ! updates.empty?
24
24
  converge_by updates do
25
25
  driver.modify_db_subnet_group(desired_options)
@@ -37,18 +37,18 @@ class Chef::Provider::AwsRdsSubnetGroup < Chef::Provisioning::AWSDriver::AWSProv
37
37
  end
38
38
  end
39
39
 
40
- # Given an existing object, return an array of update descriptions
40
+ # Given an existing subnet group, return an array of update descriptions
41
41
  # representing the updates that need to be made.
42
42
  #
43
43
  # If no updates are needed, an empty array is returned.
44
44
  #
45
- def required_updates(object)
45
+ def required_updates(subnet_group)
46
46
  ret = []
47
- if desired_options[:db_subnet_group_description] != object[:db_subnet_group_description]
47
+ if desired_options[:db_subnet_group_description] != subnet_group[:db_subnet_group_description]
48
48
  ret << " set group description to #{desired_options[:db_subnet_group_description]}"
49
49
  end
50
50
 
51
- if ! xor_array(desired_options[:subnet_ids], subnet_ids(object[:subnets])).empty?
51
+ if ! xor_array(desired_options[:subnet_ids], subnet_ids(subnet_group[:subnets])).empty?
52
52
  ret << " set subnets to #{desired_options[:subnet_ids]}"
53
53
  end
54
54
 
@@ -87,7 +87,7 @@ class Chef::Provider::AwsRouteTable < Chef::Provisioning::AWSDriver::AWSProvider
87
87
  current_route = current_routes.delete(destination_cidr_block)
88
88
  current_target = current_route.gateway_id || current_route.instance_id || current_route.network_interface_id || current_route.vpc_peering_connection_id
89
89
  if current_target != target
90
- action_handler.perform_action "reroute #{destination_cidr_block} to #{route_target} (#{target}) instead of #{current_route.target}" do
90
+ action_handler.perform_action "reroute #{destination_cidr_block} to #{route_target} (#{target}) instead of #{current_target}" do
91
91
  current_route.replace(options)
92
92
  end
93
93
  end
@@ -144,6 +144,8 @@ class Chef::Provider::AwsRouteTable < Chef::Provisioning::AWSDriver::AWSProvider
144
144
  route_target = { network_interface: route_target }
145
145
  when /^pcx-[A-Fa-f0-9]{8}$/, Chef::Resource::AwsVpcPeeringConnection, ::Aws::EC2::VpcPeeringConnection
146
146
  route_target = { vpc_peering_connection: route_target }
147
+ when /^vgw-[A-Fa-f0-9]{8}$/
148
+ route_target = { virtual_private_gateway: route_target }
147
149
  when String, Chef::Resource::AwsInstance
148
150
  route_target = { instance: route_target }
149
151
  when Chef::Resource::Machine
@@ -169,6 +171,8 @@ class Chef::Provider::AwsRouteTable < Chef::Provisioning::AWSDriver::AWSProvider
169
171
  updated_route_target[:gateway_id] = Chef::Resource::AwsInternetGateway.get_aws_object_id(value, resource: new_resource)
170
172
  when :vpc_peering_connection
171
173
  updated_route_target[:vpc_peering_connection_id] = Chef::Resource::AwsVpcPeeringConnection.get_aws_object_id(value, resource: new_resource)
174
+ when :virtual_private_gateway
175
+ updated_route_target[:gateway_id] = value
172
176
  end
173
177
  end
174
178
  updated_route_target
@@ -9,12 +9,13 @@ class Chef::Provider::AwsServerCertificate < Chef::Provisioning::AWSDriver::AWSP
9
9
 
10
10
  def create_aws_object
11
11
  converge_by "create server certificate #{new_resource.name}" do
12
- new_resource.driver.iam.server_certificates.upload(
12
+ opts = {
13
13
  :name => new_resource.name,
14
14
  :certificate_body => new_resource.certificate_body,
15
- :certificate_chain => new_resource.certificate_chain,
16
15
  :private_key => new_resource.private_key
17
- )
16
+ }
17
+ opts[:certificate_chain] = new_resource.certificate_chain if new_resource.certificate_chain
18
+ new_resource.driver.iam.server_certificates.upload(**opts)
18
19
  end
19
20
  end
20
21
 
@@ -9,6 +9,7 @@ require "chef/resource/aws_cloudsearch_domain"
9
9
  require "chef/resource/aws_dhcp_options"
10
10
  require "chef/resource/aws_ebs_volume"
11
11
  require "chef/resource/aws_eip_address"
12
+ require "chef/resource/aws_elasticsearch_domain"
12
13
  require "chef/resource/aws_iam_role"
13
14
  require "chef/resource/aws_iam_instance_profile"
14
15
  require "chef/resource/aws_image"
@@ -270,8 +270,9 @@ class AWSProvider < Chef::Provider::LWRPBase
270
270
 
271
271
  Retryable.retryable(:tries => tries, :sleep => sleep) do |retries, exception|
272
272
  action_handler.report_progress "waited #{retries*sleep}/#{tries*sleep}s for <#{aws_object.class}:#{aws_object.id}>##{query_method} state to change to #{expected_responses.inspect}..."
273
- Chef::Log.debug("Current exception in wait_for is #{exception.inspect}")
273
+ Chef::Log.debug("Current exception in wait_for is #{exception.inspect}") if exception
274
274
  begin
275
+ yield(aws_object) if block_given?
275
276
  current_response = aws_object.send(query_method)
276
277
  Chef::Log.debug("Current response in wait_for from [#{query_method}] is #{current_response}")
277
278
  unless expected_responses.include?(current_response)
@@ -33,7 +33,9 @@ AWS_V2_SERVICES = {
33
33
  "Route53" => "route53",
34
34
  "S3" => "s3",
35
35
  "ElasticLoadBalancing" => "elb",
36
+ "ElasticsearchService" => "elasticsearch",
36
37
  "IAM" => "iam",
38
+ "RDS" => "rds",
37
39
  }
38
40
  Aws.eager_autoload!(:services => AWS_V2_SERVICES.keys)
39
41
 
@@ -160,11 +162,12 @@ module AWSDriver
160
162
  def allocate_load_balancer(action_handler, lb_spec, lb_options, machine_specs)
161
163
  lb_options = (lb_options || {}).to_h
162
164
  lb_options = AWSResource.lookup_options(lb_options, managed_entry_store: lb_spec.managed_entry_store, driver: self)
163
- # We delete the attributes and a health check here because they are not valid in the create call
165
+ # We delete the attributes, tags, health check, and sticky sessions here because they are not valid in the create call
164
166
  # and must be applied afterward
165
167
  lb_attributes = lb_options.delete(:attributes)
166
168
  lb_aws_tags = lb_options.delete(:aws_tags)
167
169
  health_check = lb_options.delete(:health_check)
170
+ sticky_sessions = lb_options.delete(:sticky_sessions)
168
171
 
169
172
  old_elb = nil
170
173
  actual_elb = load_balancer_for(lb_spec)
@@ -390,6 +393,61 @@ module AWSDriver
390
393
  end
391
394
  end
392
395
 
396
+ # Update the load balancer sticky sessions
397
+ if sticky_sessions
398
+ policy_name = "#{actual_elb.name}-sticky-session-policy"
399
+ policies = elb.client.describe_load_balancer_policies(load_balancer_name: actual_elb.name)
400
+
401
+ existing_cookie_policy = policies[:policy_descriptions].detect { |pd| pd[:policy_type_name] == 'AppCookieStickinessPolicyType' && pd[:policy_name] == policy_name}
402
+ existing_cookie_name = existing_cookie_policy ? (existing_cookie_policy[:policy_attribute_descriptions].detect { |pad| pad[:attribute_name] == 'CookieName' })[:attribute_value] : nil
403
+ desired_cookie_name = sticky_sessions[:cookie_name]
404
+
405
+ # Create or update the policy to have the desired cookie_name
406
+ if existing_cookie_policy.nil?
407
+ perform_action.call(" creating sticky sessions with cookie_name #{desired_cookie_name}") do
408
+ elb.client.create_app_cookie_stickiness_policy(
409
+ load_balancer_name: actual_elb.name,
410
+ policy_name: policy_name,
411
+ cookie_name: desired_cookie_name
412
+ )
413
+ end
414
+ elsif existing_cookie_name && existing_cookie_name != desired_cookie_name
415
+ perform_action.call(" updating sticky sessions from cookie_name #{existing_cookie_name} to cookie_name #{desired_cookie_name}") do
416
+ elb.client.delete_load_balancer_policy(
417
+ load_balancer_name: actual_elb.name,
418
+ policy_name: policy_name
419
+ )
420
+ elb.client.create_app_cookie_stickiness_policy(
421
+ load_balancer_name: actual_elb.name,
422
+ policy_name: policy_name,
423
+ cookie_name: desired_cookie_name
424
+ )
425
+ end
426
+ end
427
+
428
+ # Ensure the policy is attached to the appropriate listener
429
+ elb_description = elb.client.describe_load_balancers(load_balancer_names: [actual_elb.name])[:load_balancer_descriptions].first
430
+ listeners = elb_description[:listener_descriptions]
431
+
432
+ sticky_sessions[:ports].each do |ss_port|
433
+ listener = listeners.detect { |ld| ld[:listener][:load_balancer_port] == ss_port }
434
+
435
+ unless listener.nil?
436
+ policy_names = listener[:policy_names]
437
+
438
+ unless policy_names.include?(policy_name)
439
+ policy_names << policy_name
440
+
441
+ elb.client.set_load_balancer_policies_of_listener(
442
+ load_balancer_name: actual_elb.name,
443
+ load_balancer_port: ss_port,
444
+ policy_names: policy_names
445
+ )
446
+ end
447
+ end
448
+ end
449
+ end
450
+
393
451
  # Update instance list, but only if there are machines specified
394
452
  if machine_specs
395
453
  assigned_instance_ids = actual_elb.instances.map { |i| i.instance_id }
@@ -521,6 +579,8 @@ module AWSDriver
521
579
  aws_image image_spec.name do
522
580
  action :destroy
523
581
  driver d
582
+ chef_server image_spec.managed_entry_store.chef_server
583
+ managed_entry_store image_spec.managed_entry_store
524
584
  end
525
585
  end
526
586
  end
@@ -597,7 +657,7 @@ EOD
597
657
  end
598
658
  }
599
659
  end
600
- wait_for_transport(action_handler, machine_spec, machine_options)
660
+ wait_for_transport(action_handler, machine_spec, machine_options, instance)
601
661
  machine_for(machine_spec, machine_options, instance)
602
662
  end
603
663
 
@@ -630,6 +690,8 @@ EOD
630
690
  aws_instance machine_spec.name do
631
691
  action :destroy
632
692
  driver d
693
+ chef_server machine_spec.managed_entry_store.chef_server
694
+ managed_entry_store machine_spec.managed_entry_store
633
695
  end
634
696
  end
635
697
 
@@ -1041,70 +1103,77 @@ EOD
1041
1103
 
1042
1104
  def wait_until_ready_image(action_handler, image_spec, image=nil)
1043
1105
  wait_until_image(action_handler, image_spec, image) { image.state == :available }
1106
+ action_handler.report_progress "Image #{image_spec.name} is now ready"
1044
1107
  end
1045
1108
 
1046
1109
  def wait_until_image(action_handler, image_spec, image=nil, &block)
1047
1110
  image ||= image_for(image_spec)
1048
- time_elapsed = 0
1049
1111
  sleep_time = 10
1050
- max_wait_time = Chef::Config.chef_provisioning[:image_max_wait_time] || 300
1051
- if !yield(image)
1052
- action_handler.report_progress "waiting for #{image_spec.name} (#{image.id} on #{driver_url}) to be ready ..."
1053
- while time_elapsed < max_wait_time && !yield(image)
1054
- action_handler.report_progress "been waiting #{time_elapsed}/#{max_wait_time} -- sleeping #{sleep_time} seconds for #{image_spec.name} (#{image.id} on #{driver_url}) to be ready ..."
1055
- sleep(sleep_time)
1056
- time_elapsed += sleep_time
1057
- end
1058
- unless yield(image)
1059
- raise "Image #{image.id} did not become ready within #{max_wait_time} seconds"
1112
+ unless yield(image)
1113
+ if action_handler.should_perform_actions
1114
+ action_handler.report_progress "waiting for #{image_spec.name} (#{image.id} on #{driver_url}) to be ready ..."
1115
+ max_wait_time = Chef::Config.chef_provisioning[:image_max_wait_time] || 300
1116
+ Retryable.retryable(
1117
+ :tries => (max_wait_time/sleep_time).to_i,
1118
+ :sleep => sleep_time,
1119
+ :matching => /did not become ready within/
1120
+ ) do |retries, exception|
1121
+ 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 ..."
1122
+ unless yield(image)
1123
+ raise "Image #{image.id} did not become ready within #{max_wait_time} seconds"
1124
+ end
1125
+ end
1060
1126
  end
1061
- action_handler.report_progress "Image #{image_spec.name} is now ready"
1062
1127
  end
1063
1128
  end
1064
1129
 
1065
1130
  def wait_until_instance_running(action_handler, machine_spec, instance=nil)
1066
- wait_until_machine(action_handler, machine_spec, "be ready", instance) { |instance|
1131
+ wait_until_machine(action_handler, machine_spec, "become ready", instance) { |instance|
1067
1132
  instance.state.name == "running"
1068
1133
  }
1069
1134
  end
1070
1135
 
1071
1136
  def wait_until_machine(action_handler, machine_spec, output_msg, instance=nil, &block)
1072
1137
  instance ||= instance_for(machine_spec)
1073
- max_attempts = ((Chef::Config.chef_provisioning[:machine_max_wait_time] || 120) / 10).floor
1074
- delay = 10
1075
- log_progress = Proc.new do |attempts, response|
1076
- 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} ..."
1077
- end
1078
- if action_handler.should_perform_actions
1079
- no_wait = yield(instance)
1080
- unless no_wait
1138
+ sleep_time = 10
1139
+ unless yield(instance)
1140
+ if action_handler.should_perform_actions
1081
1141
  action_handler.report_progress "waiting for #{machine_spec.name} (#{instance.id} on #{driver_url}) to #{output_msg} ..."
1082
- instance.wait_until(:max_attempts => max_attempts, :delay => delay, before_wait: log_progress) do |instance|
1083
- yield(instance)
1142
+ max_wait_time = Chef::Config.chef_provisioning[:machine_max_wait_time] || 120
1143
+ Retryable.retryable(
1144
+ :tries => (max_wait_time/sleep_time).to_i,
1145
+ :sleep => sleep_time,
1146
+ :matching => /did not #{output_msg} within/
1147
+ ) do |retries, exception|
1148
+ action_handler.report_progress "been waiting #{sleep_time*retries}/#{max_wait_time} -- sleeping #{sleep_time} seconds for #{machine_spec.name} (#{instance.id} on #{driver_url}) to #{output_msg} ..."
1149
+ # We have to manually reload the instance each loop, otherwise data is stale
1150
+ instance.reload
1151
+ unless yield(instance)
1152
+ raise "Instance #{machine_spec.name} (#{instance.id} on #{driver_url}) did not #{output_msg} within #{max_wait_time} seconds"
1153
+ end
1084
1154
  end
1085
1155
  end
1086
1156
  end
1087
- # We need an instance.reload here because the `wait_until` does not reload the instance it is called on,
1088
- # only the instance that is passed to the block
1089
- instance.reload
1090
1157
  end
1091
1158
 
1092
- def wait_for_transport(action_handler, machine_spec, machine_options)
1093
- instance = instance_for(machine_spec)
1094
- time_elapsed = 0
1159
+ def wait_for_transport(action_handler, machine_spec, machine_options, instance=nil)
1160
+ instance ||= instance_for(machine_spec)
1095
1161
  sleep_time = 10
1096
- max_wait_time = Chef::Config.chef_provisioning[:machine_max_wait_time] || 120
1097
1162
  transport = transport_for(machine_spec, machine_options, instance)
1098
1163
  unless transport.available?
1099
1164
  if action_handler.should_perform_actions
1100
1165
  action_handler.report_progress "waiting for #{machine_spec.name} (#{instance.id} on #{driver_url}) to be connectable (transport up and running) ..."
1101
- while time_elapsed < max_wait_time && !transport.available?
1102
- action_handler.report_progress "been waiting #{time_elapsed}/#{max_wait_time} -- sleeping #{sleep_time} seconds for #{machine_spec.name} (#{instance.id} on #{driver_url}) to be connectable ..."
1103
- sleep(sleep_time)
1104
- time_elapsed += sleep_time
1166
+ max_wait_time = Chef::Config.chef_provisioning[:machine_max_wait_time] || 120
1167
+ Retryable.retryable(
1168
+ :tries => (max_wait_time/sleep_time).to_i,
1169
+ :sleep => sleep_time,
1170
+ :matching => /did not become connectable within/
1171
+ ) do |retries, exception|
1172
+ action_handler.report_progress "been waiting #{sleep_time*retries}/#{max_wait_time} -- sleeping #{sleep_time} seconds for #{machine_spec.name} (#{instance.id} on #{driver_url}) to become connectable ..."
1173
+ unless transport.available?
1174
+ raise "Instance #{machine_spec.name} (#{instance.id} on #{driver_url}) did not become connectable within #{max_wait_time} seconds"
1175
+ end
1105
1176
  end
1106
-
1107
- action_handler.report_progress "#{machine_spec.name} is now connectable"
1108
1177
  end
1109
1178
  end
1110
1179
  end
@@ -1125,6 +1194,8 @@ EOD
1125
1194
  Provisioning.inline_resource(action_handler) do
1126
1195
  aws_key_pair default_key_name do
1127
1196
  driver driver
1197
+ chef_server machine_spec.managed_entry_store.chef_server
1198
+ managed_entry_store machine_spec.managed_entry_store
1128
1199
  allow_overwrite true
1129
1200
  end
1130
1201
  end