kitchen-ec2 3.2.0 → 3.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.
- checksums.yaml +4 -4
- data/lib/kitchen/driver/aws/client.rb +10 -0
- data/lib/kitchen/driver/aws/instance_generator.rb +46 -19
- data/lib/kitchen/driver/aws/standard_platform/amazon.rb +3 -1
- data/lib/kitchen/driver/aws/standard_platform/amazon2.rb +3 -1
- data/lib/kitchen/driver/aws/standard_platform/centos.rb +3 -1
- data/lib/kitchen/driver/aws/standard_platform/debian.rb +5 -2
- data/lib/kitchen/driver/aws/standard_platform/fedora.rb +3 -1
- data/lib/kitchen/driver/aws/standard_platform/freebsd.rb +3 -1
- data/lib/kitchen/driver/aws/standard_platform/rhel.rb +3 -1
- data/lib/kitchen/driver/aws/standard_platform/ubuntu.rb +3 -1
- data/lib/kitchen/driver/aws/standard_platform/windows.rb +3 -1
- data/lib/kitchen/driver/ec2.rb +45 -102
- data/lib/kitchen/driver/ec2_version.rb +2 -2
- metadata +9 -9
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0d6429e51c08d43c0e1084b9acc55b76feacae05bbe42b7cf3a1e35e0de70f87
|
|
4
|
+
data.tar.gz: 9f2a0adbe2866ad6a267ab8adc14d24a890b22b71b0abe272808a2a52def3933
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: aa308480b37d109ec173851aefe0098523d2a59c06481e88004bf76ccb8d87dfbd865300d2383157af13b38af47588ec2d1adf0541734f7279669a8dbcb0b673
|
|
7
|
+
data.tar.gz: 48f6f1a3dc22caf5d04079ef1579c19850e7e72558708e633537adb752969c3aac1b79702804864fac3fad9140e8d9053347c3ecde47e578e0545366d0b0b619
|
|
@@ -49,14 +49,24 @@ module Kitchen
|
|
|
49
49
|
::Aws.config.update(retry_limit: retry_limit) unless retry_limit.nil?
|
|
50
50
|
end
|
|
51
51
|
|
|
52
|
+
# create a new AWS EC2 instance
|
|
53
|
+
# @param options [Hash] has of instance options
|
|
54
|
+
# @see https://docs.aws.amazon.com/sdkforruby/api/Aws/EC2/Resource.html#create_instances-instance_method
|
|
55
|
+
# @return [Aws::EC2::Instance]
|
|
52
56
|
def create_instance(options)
|
|
53
57
|
resource.create_instances(options).first
|
|
54
58
|
end
|
|
55
59
|
|
|
60
|
+
# get an instance object given an id
|
|
61
|
+
# @param id [String] aws instance id
|
|
62
|
+
# @return [Aws::EC2::Instance]
|
|
56
63
|
def get_instance(id)
|
|
57
64
|
resource.instance(id)
|
|
58
65
|
end
|
|
59
66
|
|
|
67
|
+
# get an instance object given a spot request ID
|
|
68
|
+
# @param request_id [String] aws spot instance id
|
|
69
|
+
# @return [Aws::EC2::Instance]
|
|
60
70
|
def get_instance_from_spot_request(request_id)
|
|
61
71
|
resource.instances(
|
|
62
72
|
filters: [{
|
|
@@ -39,29 +39,34 @@ module Kitchen
|
|
|
39
39
|
@logger = logger
|
|
40
40
|
end
|
|
41
41
|
|
|
42
|
-
# Transform the provided config into the hash
|
|
42
|
+
# Transform the provided kitchen config into the hash we'll use to create the aws instance
|
|
43
43
|
# can be passed in null, others need to be ommitted if they are null
|
|
44
|
+
# Some fields can be passed in null, others need to be ommitted if they are null
|
|
45
|
+
# @return [Hash]
|
|
44
46
|
def ec2_instance_data # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
|
45
47
|
# Support for looking up security group id and subnet id using tags.
|
|
46
|
-
|
|
48
|
+
vpc_id = nil
|
|
49
|
+
client = ::Aws::EC2::Client.new(region: config[:region])
|
|
47
50
|
if config[:subnet_id].nil? && config[:subnet_filter]
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
{
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
if
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
51
|
+
subnets = client.describe_subnets(
|
|
52
|
+
filters: [
|
|
53
|
+
{
|
|
54
|
+
name: "tag:#{config[:subnet_filter][:tag]}",
|
|
55
|
+
values: [config[:subnet_filter][:value]],
|
|
56
|
+
},
|
|
57
|
+
]
|
|
58
|
+
).subnets
|
|
59
|
+
raise "The subnet tagged '#{config[:subnet_filter][:tag]}:#{config[:subnet_filter][:value]}' does not exist!" unless subnets.any?
|
|
60
|
+
|
|
61
|
+
# => Select the least-populated subnet if we have multiple matches
|
|
62
|
+
subnet = subnets.sort_by { |s| s[:available_ip_address_count] }.last
|
|
63
|
+
vpc_id = subnet.vpc_id
|
|
64
|
+
config[:subnet_id] = subnet.subnet_id
|
|
62
65
|
end
|
|
63
66
|
|
|
64
67
|
if config[:security_group_ids].nil? && config[:security_group_filter]
|
|
68
|
+
# => Grab the VPC in the case a Subnet ID rather than Filter was set
|
|
69
|
+
vpc_id ||= client.describe_subnets(subnet_ids: [config[:subnet_id]]).subnets[0].vpc_id
|
|
65
70
|
security_groups = []
|
|
66
71
|
filters = [config[:security_group_filter]].flatten
|
|
67
72
|
filters.each do |sg_filter|
|
|
@@ -72,6 +77,10 @@ module Kitchen
|
|
|
72
77
|
name: "group-name",
|
|
73
78
|
values: [sg_filter[:name]],
|
|
74
79
|
},
|
|
80
|
+
{
|
|
81
|
+
name: "vpc-id",
|
|
82
|
+
values: [vpc_id],
|
|
83
|
+
},
|
|
75
84
|
]
|
|
76
85
|
end
|
|
77
86
|
|
|
@@ -81,13 +90,17 @@ module Kitchen
|
|
|
81
90
|
name: "tag:#{sg_filter[:tag]}",
|
|
82
91
|
values: [sg_filter[:value]],
|
|
83
92
|
},
|
|
93
|
+
{
|
|
94
|
+
name: "vpc-id",
|
|
95
|
+
values: [vpc_id],
|
|
96
|
+
},
|
|
84
97
|
]
|
|
85
98
|
end
|
|
86
99
|
|
|
87
|
-
security_group =
|
|
100
|
+
security_group = client.describe_security_groups(r).security_groups
|
|
88
101
|
|
|
89
|
-
if security_group
|
|
90
|
-
security_groups.push(
|
|
102
|
+
if security_group.any?
|
|
103
|
+
security_group.each { |sg| security_groups.push(sg.group_id) }
|
|
91
104
|
else
|
|
92
105
|
raise "A Security Group matching the following filter could not be found:\n#{sg_filter}"
|
|
93
106
|
end
|
|
@@ -102,8 +115,22 @@ module Kitchen
|
|
|
102
115
|
key_name: config[:aws_ssh_key_id],
|
|
103
116
|
subnet_id: config[:subnet_id],
|
|
104
117
|
private_ip_address: config[:private_ip_address],
|
|
118
|
+
min_count: 1,
|
|
119
|
+
max_count: 1,
|
|
105
120
|
}
|
|
106
121
|
|
|
122
|
+
if config[:tags] && !config[:tags].empty?
|
|
123
|
+
tags = config[:tags].map do |k, v|
|
|
124
|
+
# we convert the value to a string because
|
|
125
|
+
# nils should be passed as an empty String
|
|
126
|
+
# and Integers need to be represented as Strings
|
|
127
|
+
{ key: k, value: v.to_s }
|
|
128
|
+
end
|
|
129
|
+
instance_tag_spec = { resource_type: "instance", tags: tags }
|
|
130
|
+
volume_tag_spec = { resource_type: "volume", tags: tags }
|
|
131
|
+
i[:tag_specifications] = [instance_tag_spec, volume_tag_spec]
|
|
132
|
+
end
|
|
133
|
+
|
|
107
134
|
availability_zone = config[:availability_zone]
|
|
108
135
|
if availability_zone
|
|
109
136
|
if availability_zone =~ /^[a-z]$/i
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
# See the License for the specific language governing permissions and
|
|
14
14
|
# limitations under the License.
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
require_relative "../standard_platform"
|
|
17
17
|
|
|
18
18
|
module Kitchen
|
|
19
19
|
module Driver
|
|
@@ -23,6 +23,8 @@ module Kitchen
|
|
|
23
23
|
class Amazon < StandardPlatform
|
|
24
24
|
StandardPlatform.platforms["amazon"] = self
|
|
25
25
|
|
|
26
|
+
# default username for this platform's ami
|
|
27
|
+
# @return [String]
|
|
26
28
|
def username
|
|
27
29
|
"ec2-user"
|
|
28
30
|
end
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
# See the License for the specific language governing permissions and
|
|
14
14
|
# limitations under the License.
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
require_relative "../standard_platform"
|
|
17
17
|
|
|
18
18
|
module Kitchen
|
|
19
19
|
module Driver
|
|
@@ -23,6 +23,8 @@ module Kitchen
|
|
|
23
23
|
class Amazon2 < StandardPlatform
|
|
24
24
|
StandardPlatform.platforms["amazon2"] = self
|
|
25
25
|
|
|
26
|
+
# default username for this platform's ami
|
|
27
|
+
# @return [String]
|
|
26
28
|
def username
|
|
27
29
|
"ec2-user"
|
|
28
30
|
end
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
# See the License for the specific language governing permissions and
|
|
14
14
|
# limitations under the License.
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
require_relative "../standard_platform"
|
|
17
17
|
|
|
18
18
|
module Kitchen
|
|
19
19
|
module Driver
|
|
@@ -23,6 +23,8 @@ module Kitchen
|
|
|
23
23
|
class Centos < StandardPlatform
|
|
24
24
|
StandardPlatform.platforms["centos"] = self
|
|
25
25
|
|
|
26
|
+
# default username for this platform's ami
|
|
27
|
+
# @return [String]
|
|
26
28
|
def username
|
|
27
29
|
# Centos 6.x images use root as the username (but the "centos 6"
|
|
28
30
|
# updateable image uses "centos")
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
# See the License for the specific language governing permissions and
|
|
14
14
|
# limitations under the License.
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
require_relative "../standard_platform"
|
|
17
17
|
|
|
18
18
|
module Kitchen
|
|
19
19
|
module Driver
|
|
@@ -26,14 +26,17 @@ module Kitchen
|
|
|
26
26
|
# 10/11 are listed last since we default to the first item in the hash
|
|
27
27
|
# and 10/11 are not released yet. When they're released move them up
|
|
28
28
|
DEBIAN_CODENAMES = {
|
|
29
|
+
10 => "buster",
|
|
29
30
|
9 => "stretch",
|
|
30
31
|
8 => "jessie",
|
|
31
32
|
7 => "wheezy",
|
|
32
33
|
6 => "squeeze",
|
|
33
34
|
11 => "bullseye",
|
|
34
|
-
|
|
35
|
+
12 => "bookworm",
|
|
35
36
|
}.freeze
|
|
36
37
|
|
|
38
|
+
# default username for this platform's ami
|
|
39
|
+
# @return [String]
|
|
37
40
|
def username
|
|
38
41
|
"admin"
|
|
39
42
|
end
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
# See the License for the specific language governing permissions and
|
|
14
14
|
# limitations under the License.
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
require_relative "../standard_platform"
|
|
17
17
|
|
|
18
18
|
module Kitchen
|
|
19
19
|
module Driver
|
|
@@ -23,6 +23,8 @@ module Kitchen
|
|
|
23
23
|
class Fedora < StandardPlatform
|
|
24
24
|
StandardPlatform.platforms["fedora"] = self
|
|
25
25
|
|
|
26
|
+
# default username for this platform's ami
|
|
27
|
+
# @return [String]
|
|
26
28
|
def username
|
|
27
29
|
"fedora"
|
|
28
30
|
end
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
# See the License for the specific language governing permissions and
|
|
14
14
|
# limitations under the License.
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
require_relative "../standard_platform"
|
|
17
17
|
|
|
18
18
|
module Kitchen
|
|
19
19
|
module Driver
|
|
@@ -23,6 +23,8 @@ module Kitchen
|
|
|
23
23
|
class Freebsd < StandardPlatform
|
|
24
24
|
StandardPlatform.platforms["freebsd"] = self
|
|
25
25
|
|
|
26
|
+
# default username for this platform's ami
|
|
27
|
+
# @return [String]
|
|
26
28
|
def username
|
|
27
29
|
"ec2-user"
|
|
28
30
|
end
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
# See the License for the specific language governing permissions and
|
|
14
14
|
# limitations under the License.
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
require_relative "../standard_platform"
|
|
17
17
|
|
|
18
18
|
module Kitchen
|
|
19
19
|
module Driver
|
|
@@ -29,6 +29,8 @@ module Kitchen
|
|
|
29
29
|
super(driver, "rhel", version, architecture)
|
|
30
30
|
end
|
|
31
31
|
|
|
32
|
+
# default username for this platform's ami
|
|
33
|
+
# @return [String]
|
|
32
34
|
def username
|
|
33
35
|
(version && version.to_f < 6.4) ? "root" : "ec2-user"
|
|
34
36
|
end
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
# See the License for the specific language governing permissions and
|
|
14
14
|
# limitations under the License.
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
require_relative "../standard_platform"
|
|
17
17
|
|
|
18
18
|
module Kitchen
|
|
19
19
|
module Driver
|
|
@@ -23,6 +23,8 @@ module Kitchen
|
|
|
23
23
|
class Ubuntu < StandardPlatform
|
|
24
24
|
StandardPlatform.platforms["ubuntu"] = self
|
|
25
25
|
|
|
26
|
+
# default username for this platform's ami
|
|
27
|
+
# @return [String]
|
|
26
28
|
def username
|
|
27
29
|
"ubuntu"
|
|
28
30
|
end
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
# See the License for the specific language governing permissions and
|
|
14
14
|
# limitations under the License.
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
require_relative "../standard_platform"
|
|
17
17
|
|
|
18
18
|
module Kitchen
|
|
19
19
|
module Driver
|
|
@@ -23,6 +23,8 @@ module Kitchen
|
|
|
23
23
|
class Windows < StandardPlatform
|
|
24
24
|
StandardPlatform.platforms["windows"] = self
|
|
25
25
|
|
|
26
|
+
# default username for this platform's ami
|
|
27
|
+
# @return [String]
|
|
26
28
|
def username
|
|
27
29
|
"administrator"
|
|
28
30
|
end
|
data/lib/kitchen/driver/ec2.rb
CHANGED
|
@@ -227,7 +227,7 @@ module Kitchen
|
|
|
227
227
|
|
|
228
228
|
if config[:spot_price]
|
|
229
229
|
# Spot instance when a price is set
|
|
230
|
-
server = with_request_limit_backoff(state) { submit_spots
|
|
230
|
+
server = with_request_limit_backoff(state) { submit_spots }
|
|
231
231
|
else
|
|
232
232
|
# On-demand instance
|
|
233
233
|
server = with_request_limit_backoff(state) { submit_server }
|
|
@@ -238,32 +238,16 @@ module Kitchen
|
|
|
238
238
|
server.wait_until_exists(before_attempt: logging_proc)
|
|
239
239
|
end
|
|
240
240
|
|
|
241
|
+
state[:server_id] = server.id
|
|
242
|
+
info("EC2 instance <#{state[:server_id]}> created.")
|
|
243
|
+
|
|
241
244
|
# See https://github.com/aws/aws-sdk-ruby/issues/859
|
|
242
|
-
#
|
|
243
|
-
# Waiting can also fail, so we have to also retry on that. If it means we re-tag the
|
|
244
|
-
# instance, so be it.
|
|
245
|
-
# Tagging an instance is possible before volumes are attached. Tagging the volumes after
|
|
246
|
-
# instance creation is consistent.
|
|
245
|
+
# Waiting can fail, so we have to retry on that.
|
|
247
246
|
Retryable.retryable(
|
|
248
247
|
tries: 10,
|
|
249
248
|
sleep: lambda { |n| [2**n, 30].min },
|
|
250
249
|
on: ::Aws::EC2::Errors::InvalidInstanceIDNotFound
|
|
251
250
|
) do |r, _|
|
|
252
|
-
info("Attempting to tag the instance, #{r} retries")
|
|
253
|
-
tag_server(server)
|
|
254
|
-
|
|
255
|
-
# Get information about the AMI (image) used to create the image.
|
|
256
|
-
image_data = ec2.client.describe_images({ image_ids: [server.image_id] })[0][0]
|
|
257
|
-
|
|
258
|
-
state[:server_id] = server.id
|
|
259
|
-
info("EC2 instance <#{state[:server_id]}> created.")
|
|
260
|
-
|
|
261
|
-
# instance-store backed images do not have attached volumes, so only
|
|
262
|
-
# wait for the volumes to be ready if the instance EBS-backed.
|
|
263
|
-
if image_data.root_device_type == "ebs"
|
|
264
|
-
wait_until_volumes_ready(server, state)
|
|
265
|
-
tag_volumes(server)
|
|
266
|
-
end
|
|
267
251
|
wait_until_ready(server, state)
|
|
268
252
|
end
|
|
269
253
|
|
|
@@ -277,7 +261,7 @@ module Kitchen
|
|
|
277
261
|
|
|
278
262
|
info("EC2 instance <#{state[:server_id]}> ready (hostname: #{state[:hostname]}).")
|
|
279
263
|
instance.transport.connection(state).wait_until_ready
|
|
280
|
-
create_ec2_json(state) if instance.provisioner.name =~ /chef/
|
|
264
|
+
create_ec2_json(state) if instance.provisioner.name =~ /chef/i
|
|
281
265
|
debug("ec2:create '#{state[:hostname]}'")
|
|
282
266
|
rescue Exception
|
|
283
267
|
# Clean up any auto-created security groups or keys on the way out.
|
|
@@ -291,14 +275,11 @@ module Kitchen
|
|
|
291
275
|
server = ec2.get_instance(state[:server_id])
|
|
292
276
|
unless server.nil?
|
|
293
277
|
instance.transport.connection(state).close
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
spot_instance_request_ids: [state[:spot_request_id]]
|
|
300
|
-
)
|
|
301
|
-
state.delete(:spot_request_id)
|
|
278
|
+
begin
|
|
279
|
+
server.terminate
|
|
280
|
+
rescue ::Aws::EC2::Errors::InvalidInstanceIDNotFound => e
|
|
281
|
+
warn("Received #{e}, instance was probably already destroyed. Ignoring")
|
|
282
|
+
end
|
|
302
283
|
end
|
|
303
284
|
# If we are going to clean up an automatic security group, we need
|
|
304
285
|
# to wait for the instance to shut down. This slightly breaks the
|
|
@@ -405,15 +386,14 @@ module Kitchen
|
|
|
405
386
|
@instance_generator = Aws::InstanceGenerator.new(config, ec2, instance.logger)
|
|
406
387
|
end
|
|
407
388
|
|
|
408
|
-
#
|
|
389
|
+
# AWS helper for creating the instance
|
|
409
390
|
def submit_server
|
|
410
391
|
instance_data = instance_generator.ec2_instance_data
|
|
411
392
|
debug("Creating EC2 instance in region #{config[:region]} with properties:")
|
|
412
393
|
instance_data.each do |key, value|
|
|
413
394
|
debug("- #{key} = #{value.inspect}")
|
|
414
395
|
end
|
|
415
|
-
|
|
416
|
-
instance_data[:max_count] = 1
|
|
396
|
+
|
|
417
397
|
ec2.create_instance(instance_data)
|
|
418
398
|
end
|
|
419
399
|
|
|
@@ -441,7 +421,7 @@ module Kitchen
|
|
|
441
421
|
configs
|
|
442
422
|
end
|
|
443
423
|
|
|
444
|
-
def submit_spots
|
|
424
|
+
def submit_spots
|
|
445
425
|
configs = [config]
|
|
446
426
|
expanded = []
|
|
447
427
|
keys = %i{instance_type subnet_id}
|
|
@@ -454,40 +434,22 @@ module Kitchen
|
|
|
454
434
|
expanded = []
|
|
455
435
|
end
|
|
456
436
|
|
|
437
|
+
errs = []
|
|
457
438
|
configs.each do |conf|
|
|
458
439
|
begin
|
|
459
440
|
@config = conf
|
|
460
|
-
return submit_spot
|
|
461
|
-
rescue
|
|
441
|
+
return submit_spot
|
|
442
|
+
rescue => e
|
|
443
|
+
errs.append(e)
|
|
462
444
|
end
|
|
463
445
|
end
|
|
464
|
-
|
|
465
|
-
raise "Could not create a spot"
|
|
446
|
+
raise ["Could not create a spot instance:", errs].flatten.join("\n")
|
|
466
447
|
end
|
|
467
448
|
|
|
468
|
-
def submit_spot
|
|
449
|
+
def submit_spot
|
|
469
450
|
debug("Creating EC2 Spot Instance..")
|
|
451
|
+
instance_data = instance_generator.ec2_instance_data
|
|
470
452
|
|
|
471
|
-
spot_request_id = create_spot_request
|
|
472
|
-
# deleting the instance cancels the request, but deleting the request
|
|
473
|
-
# does not affect the instance
|
|
474
|
-
state[:spot_request_id] = spot_request_id
|
|
475
|
-
ec2.client.wait_until(
|
|
476
|
-
:spot_instance_request_fulfilled,
|
|
477
|
-
spot_instance_request_ids: [spot_request_id]
|
|
478
|
-
) do |w|
|
|
479
|
-
w.max_attempts = config[:spot_wait] / config[:retryable_sleep]
|
|
480
|
-
w.delay = config[:retryable_sleep]
|
|
481
|
-
w.before_attempt do |attempts|
|
|
482
|
-
c = attempts * config[:retryable_sleep]
|
|
483
|
-
t = config[:spot_wait]
|
|
484
|
-
info "Waited #{c}/#{t}s for spot request <#{spot_request_id}> to become fulfilled."
|
|
485
|
-
end
|
|
486
|
-
end
|
|
487
|
-
ec2.get_instance_from_spot_request(spot_request_id)
|
|
488
|
-
end
|
|
489
|
-
|
|
490
|
-
def create_spot_request
|
|
491
453
|
request_duration = config[:spot_wait]
|
|
492
454
|
config_spot_price = config[:spot_price].to_s
|
|
493
455
|
if %w{ondemand on-demand}.include?(config_spot_price)
|
|
@@ -495,56 +457,36 @@ module Kitchen
|
|
|
495
457
|
else
|
|
496
458
|
spot_price = config_spot_price
|
|
497
459
|
end
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
launch_specification: instance_generator.ec2_instance_data,
|
|
460
|
+
spot_options = {
|
|
461
|
+
spot_instance_type: "persistent", # Cannot use one-time with valid_until
|
|
501
462
|
valid_until: Time.now + request_duration,
|
|
463
|
+
instance_interruption_behavior: "stop",
|
|
502
464
|
}
|
|
503
465
|
if config[:block_duration_minutes]
|
|
504
|
-
|
|
466
|
+
spot_options[:block_duration_minutes] = config[:block_duration_minutes]
|
|
505
467
|
end
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
response[:spot_instance_requests][0][:spot_instance_request_id]
|
|
509
|
-
end
|
|
510
|
-
|
|
511
|
-
def tag_server(server)
|
|
512
|
-
if config[:tags] && !config[:tags].empty?
|
|
513
|
-
tags = config[:tags].map do |k, v|
|
|
514
|
-
# we convert the value to a string because
|
|
515
|
-
# nils should be passed as an empty String
|
|
516
|
-
# and Integers need to be represented as Strings
|
|
517
|
-
{ key: k.to_s, value: v.to_s }
|
|
518
|
-
end
|
|
519
|
-
server.create_tags(tags: tags)
|
|
468
|
+
unless spot_price == "" # i.e. on-demand
|
|
469
|
+
spot_options[:max_price] = spot_price
|
|
520
470
|
end
|
|
521
|
-
end
|
|
522
471
|
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
end
|
|
528
|
-
server.volumes.each do |volume|
|
|
529
|
-
volume.create_tags(tags: tags)
|
|
530
|
-
end
|
|
531
|
-
end
|
|
532
|
-
end
|
|
472
|
+
instance_data[:instance_market_options] = {
|
|
473
|
+
market_type: "spot",
|
|
474
|
+
spot_options: spot_options,
|
|
475
|
+
}
|
|
533
476
|
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
(described_volume_count > 0) && (described_volume_count == ready_volume_count)
|
|
477
|
+
# The preferred way to create a spot instance is via request_spot_instances()
|
|
478
|
+
# However, it does not allow for tagging to occur at creation time.
|
|
479
|
+
# create_instances() allows creation of tagged spot instances, but does
|
|
480
|
+
# not retry if the price could not be satisfied immediately.
|
|
481
|
+
Retryable.retryable(
|
|
482
|
+
tries: config[:spot_wait] / config[:retryable_sleep],
|
|
483
|
+
sleep: lambda { |_n| config[:retryable_sleep] },
|
|
484
|
+
on: ::Aws::EC2::Errors::SpotMaxPriceTooLow
|
|
485
|
+
) do |retries|
|
|
486
|
+
c = retries * config[:retryable_sleep]
|
|
487
|
+
t = config[:spot_wait]
|
|
488
|
+
info "Waited #{c}/#{t}s for spot request to become fulfilled."
|
|
489
|
+
ec2.create_instance(instance_data)
|
|
548
490
|
end
|
|
549
491
|
end
|
|
550
492
|
|
|
@@ -788,6 +730,7 @@ module Kitchen
|
|
|
788
730
|
elsif config[:subnet_filter]
|
|
789
731
|
subnets = ec2.client.describe_subnets(filters: [{ name: "tag:#{config[:subnet_filter][:tag]}", values: [config[:subnet_filter][:value]] }]).subnets
|
|
790
732
|
raise "Subnets with tag '#{config[:subnet_filter][:tag]}=#{config[:subnet_filter][:value]}' not found during security group creation" if subnets.empty?
|
|
733
|
+
|
|
791
734
|
subnets.first.vpc_id
|
|
792
735
|
else
|
|
793
736
|
# Try to check for a default VPC.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
#
|
|
3
3
|
# Author:: Fletcher Nichol (<fnichol@nichol.ca>)
|
|
4
4
|
#
|
|
5
|
-
# Copyright::
|
|
5
|
+
# Copyright:: Chef Software, Inc.
|
|
6
6
|
# Copyright:: 2012-2018, Fletcher Nichol
|
|
7
7
|
#
|
|
8
8
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -22,6 +22,6 @@ module Kitchen
|
|
|
22
22
|
module Driver
|
|
23
23
|
|
|
24
24
|
# Version string for EC2 Test Kitchen driver
|
|
25
|
-
EC2_VERSION = "3.
|
|
25
|
+
EC2_VERSION = "3.7.0".freeze
|
|
26
26
|
end
|
|
27
27
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: kitchen-ec2
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.
|
|
4
|
+
version: 3.7.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Fletcher Nichol
|
|
8
|
-
autorequire:
|
|
8
|
+
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2020-07-02 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: test-kitchen
|
|
@@ -168,14 +168,14 @@ dependencies:
|
|
|
168
168
|
requirements:
|
|
169
169
|
- - '='
|
|
170
170
|
- !ruby/object:Gem::Version
|
|
171
|
-
version:
|
|
171
|
+
version: 1.1.2
|
|
172
172
|
type: :development
|
|
173
173
|
prerelease: false
|
|
174
174
|
version_requirements: !ruby/object:Gem::Requirement
|
|
175
175
|
requirements:
|
|
176
176
|
- - '='
|
|
177
177
|
- !ruby/object:Gem::Version
|
|
178
|
-
version:
|
|
178
|
+
version: 1.1.2
|
|
179
179
|
- !ruby/object:Gem::Dependency
|
|
180
180
|
name: climate_control
|
|
181
181
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -216,7 +216,7 @@ homepage: https://github.com/test-kitchen/kitchen-ec2
|
|
|
216
216
|
licenses:
|
|
217
217
|
- Apache-2.0
|
|
218
218
|
metadata: {}
|
|
219
|
-
post_install_message:
|
|
219
|
+
post_install_message:
|
|
220
220
|
rdoc_options: []
|
|
221
221
|
require_paths:
|
|
222
222
|
- lib
|
|
@@ -224,15 +224,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
224
224
|
requirements:
|
|
225
225
|
- - ">="
|
|
226
226
|
- !ruby/object:Gem::Version
|
|
227
|
-
version: '2.
|
|
227
|
+
version: '2.4'
|
|
228
228
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
229
229
|
requirements:
|
|
230
230
|
- - ">="
|
|
231
231
|
- !ruby/object:Gem::Version
|
|
232
232
|
version: '0'
|
|
233
233
|
requirements: []
|
|
234
|
-
rubygems_version: 3.
|
|
235
|
-
signing_key:
|
|
234
|
+
rubygems_version: 3.1.2
|
|
235
|
+
signing_key:
|
|
236
236
|
specification_version: 4
|
|
237
237
|
summary: A Test Kitchen Driver for Amazon EC2
|
|
238
238
|
test_files: []
|