kitchen-ec2 3.3.0 → 3.7.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/kitchen/driver/aws/client.rb +10 -0
- data/lib/kitchen/driver/aws/instance_generator.rb +21 -3
- data/lib/kitchen/driver/aws/standard_platform/amazon.rb +2 -0
- data/lib/kitchen/driver/aws/standard_platform/amazon2.rb +2 -0
- data/lib/kitchen/driver/aws/standard_platform/centos.rb +27 -2
- data/lib/kitchen/driver/aws/standard_platform/debian.rb +4 -1
- data/lib/kitchen/driver/aws/standard_platform/fedora.rb +2 -0
- data/lib/kitchen/driver/aws/standard_platform/freebsd.rb +2 -0
- data/lib/kitchen/driver/aws/standard_platform/rhel.rb +2 -0
- data/lib/kitchen/driver/aws/standard_platform/ubuntu.rb +2 -0
- data/lib/kitchen/driver/aws/standard_platform/windows.rb +2 -0
- data/lib/kitchen/driver/ec2.rb +64 -99
- data/lib/kitchen/driver/ec2_version.rb +2 -2
- metadata +6 -48
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: effb6d0cc14377657291cd970e2a6d50680d91df937b6799f0a942a2fba59994
|
4
|
+
data.tar.gz: a2a0b678c22cf3da32be2ee90cb542cc2c2dff015fb3563ea7783b85ddd57649
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2761f62c4647000ee4b12ac11a0080f49bb5492c296e08a22c598d1bfb0a0ea993b7d0409c04003d7819d7f287dd9fd65b611f2135c8edf69a5e36421549ea2c
|
7
|
+
data.tar.gz: 96b9d6c0062d85baafa9febca4fe0567f2659dc505c3e89da85caa3b6f82590f5a981d8df2907ee1f15709374e1e31f833f4cbb940a87b83283086e11084adab
|
@@ -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,8 +39,10 @@ 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
|
@@ -56,8 +58,10 @@ module Kitchen
|
|
56
58
|
).subnets
|
57
59
|
raise "The subnet tagged '#{config[:subnet_filter][:tag]}:#{config[:subnet_filter][:value]}' does not exist!" unless subnets.any?
|
58
60
|
|
59
|
-
|
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
|
61
65
|
end
|
62
66
|
|
63
67
|
if config[:security_group_ids].nil? && config[:security_group_filter]
|
@@ -111,8 +115,22 @@ module Kitchen
|
|
111
115
|
key_name: config[:aws_ssh_key_id],
|
112
116
|
subnet_id: config[:subnet_id],
|
113
117
|
private_ip_address: config[:private_ip_address],
|
118
|
+
min_count: 1,
|
119
|
+
max_count: 1,
|
114
120
|
}
|
115
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
|
+
|
116
134
|
availability_zone = config[:availability_zone]
|
117
135
|
if availability_zone
|
118
136
|
if availability_zone =~ /^[a-z]$/i
|
@@ -23,6 +23,16 @@ module Kitchen
|
|
23
23
|
class Centos < StandardPlatform
|
24
24
|
StandardPlatform.platforms["centos"] = self
|
25
25
|
|
26
|
+
CENTOS_OWNER_ID = "125523088429".freeze
|
27
|
+
PRODUCT_CODES = {
|
28
|
+
"6" => "6x5jmcajty9edm3f211pqjfn2",
|
29
|
+
"7" => "aw0evgkw8e5c1q413zgy5pjce",
|
30
|
+
# It appears that v8 is not published to the
|
31
|
+
# AWS marketplace and hence does not have a product code
|
32
|
+
}.freeze
|
33
|
+
|
34
|
+
# default username for this platform's ami
|
35
|
+
# @return [String]
|
26
36
|
def username
|
27
37
|
# Centos 6.x images use root as the username (but the "centos 6"
|
28
38
|
# updateable image uses "centos")
|
@@ -32,10 +42,25 @@ module Kitchen
|
|
32
42
|
end
|
33
43
|
|
34
44
|
def image_search
|
45
|
+
# Version 8+ are published directly, not to the AWS marketplace. Use OWNER ID.
|
35
46
|
search = {
|
36
|
-
"owner-
|
37
|
-
"name" => ["CentOS
|
47
|
+
"owner-id" => CENTOS_OWNER_ID,
|
48
|
+
"name" => ["CentOS #{version}*", "CentOS-#{version}*-GA-*"],
|
38
49
|
}
|
50
|
+
|
51
|
+
if version && version.split(".").first.to_i < 8
|
52
|
+
# Versions <8 are published to the AWS marketplace and use a different naming convention
|
53
|
+
search = {
|
54
|
+
"owner-alias" => "aws-marketplace",
|
55
|
+
"name" => ["CentOS Linux #{version}*", "CentOS-#{version}*-GA-*"],
|
56
|
+
}
|
57
|
+
# For versions published to aws-marketplace, additionally filter on product code to
|
58
|
+
# avoid non-official AMIs. Can't use CentOS owner ID here, as the owner ID is that of aws marketplace.
|
59
|
+
# https://github.com/test-kitchen/kitchen-ec2/issues/456
|
60
|
+
PRODUCT_CODES.keys.each do |major_version|
|
61
|
+
search["product-code"] = PRODUCT_CODES[major_version] if version.start_with?(major_version)
|
62
|
+
end
|
63
|
+
end
|
39
64
|
search["architecture"] = architecture if architecture
|
40
65
|
search
|
41
66
|
end
|
@@ -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
|
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
|
|
@@ -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,10 +421,34 @@ 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
|
-
keys = %i{instance_type
|
427
|
+
keys = %i{instance_type}
|
428
|
+
|
429
|
+
unless config[:subnet_filter]
|
430
|
+
# => Use explicitly specified subnets
|
431
|
+
keys << :subnet_id
|
432
|
+
else
|
433
|
+
# => Enable cascading through matching subnets
|
434
|
+
client = ::Aws::EC2::Client.new(region: config[:region])
|
435
|
+
subnets = client.describe_subnets(
|
436
|
+
filters: [
|
437
|
+
{
|
438
|
+
name: "tag:#{config[:subnet_filter][:tag]}",
|
439
|
+
values: [config[:subnet_filter][:value]],
|
440
|
+
},
|
441
|
+
]
|
442
|
+
).subnets
|
443
|
+
raise "A subnet matching '#{config[:subnet_filter][:tag]}:#{config[:subnet_filter][:value]}' does not exist!" unless subnets.any?
|
444
|
+
|
445
|
+
configs = subnets.map do |subnet|
|
446
|
+
new_config = config.clone
|
447
|
+
new_config[:subnet_id] = subnet.subnet_id
|
448
|
+
new_config[:subnet_filter] = nil
|
449
|
+
new_config
|
450
|
+
end
|
451
|
+
end
|
448
452
|
|
449
453
|
keys.each do |key|
|
450
454
|
configs.each do |conf|
|
@@ -458,7 +462,7 @@ module Kitchen
|
|
458
462
|
configs.each do |conf|
|
459
463
|
begin
|
460
464
|
@config = conf
|
461
|
-
return submit_spot
|
465
|
+
return submit_spot
|
462
466
|
rescue => e
|
463
467
|
errs.append(e)
|
464
468
|
end
|
@@ -466,29 +470,10 @@ module Kitchen
|
|
466
470
|
raise ["Could not create a spot instance:", errs].flatten.join("\n")
|
467
471
|
end
|
468
472
|
|
469
|
-
def submit_spot
|
473
|
+
def submit_spot
|
470
474
|
debug("Creating EC2 Spot Instance..")
|
475
|
+
instance_data = instance_generator.ec2_instance_data
|
471
476
|
|
472
|
-
spot_request_id = create_spot_request
|
473
|
-
# deleting the instance cancels the request, but deleting the request
|
474
|
-
# does not affect the instance
|
475
|
-
state[:spot_request_id] = spot_request_id
|
476
|
-
ec2.client.wait_until(
|
477
|
-
:spot_instance_request_fulfilled,
|
478
|
-
spot_instance_request_ids: [spot_request_id]
|
479
|
-
) do |w|
|
480
|
-
w.max_attempts = config[:spot_wait] / config[:retryable_sleep]
|
481
|
-
w.delay = config[:retryable_sleep]
|
482
|
-
w.before_attempt do |attempts|
|
483
|
-
c = attempts * config[:retryable_sleep]
|
484
|
-
t = config[:spot_wait]
|
485
|
-
info "Waited #{c}/#{t}s for spot request <#{spot_request_id}> to become fulfilled."
|
486
|
-
end
|
487
|
-
end
|
488
|
-
ec2.get_instance_from_spot_request(spot_request_id)
|
489
|
-
end
|
490
|
-
|
491
|
-
def create_spot_request
|
492
477
|
request_duration = config[:spot_wait]
|
493
478
|
config_spot_price = config[:spot_price].to_s
|
494
479
|
if %w{ondemand on-demand}.include?(config_spot_price)
|
@@ -496,56 +481,36 @@ module Kitchen
|
|
496
481
|
else
|
497
482
|
spot_price = config_spot_price
|
498
483
|
end
|
499
|
-
|
500
|
-
|
501
|
-
launch_specification: instance_generator.ec2_instance_data,
|
484
|
+
spot_options = {
|
485
|
+
spot_instance_type: "persistent", # Cannot use one-time with valid_until
|
502
486
|
valid_until: Time.now + request_duration,
|
487
|
+
instance_interruption_behavior: "stop",
|
503
488
|
}
|
504
489
|
if config[:block_duration_minutes]
|
505
|
-
|
490
|
+
spot_options[:block_duration_minutes] = config[:block_duration_minutes]
|
506
491
|
end
|
507
|
-
|
508
|
-
|
509
|
-
response[:spot_instance_requests][0][:spot_instance_request_id]
|
510
|
-
end
|
511
|
-
|
512
|
-
def tag_server(server)
|
513
|
-
if config[:tags] && !config[:tags].empty?
|
514
|
-
tags = config[:tags].map do |k, v|
|
515
|
-
# we convert the value to a string because
|
516
|
-
# nils should be passed as an empty String
|
517
|
-
# and Integers need to be represented as Strings
|
518
|
-
{ key: k.to_s, value: v.to_s }
|
519
|
-
end
|
520
|
-
server.create_tags(tags: tags)
|
492
|
+
unless spot_price == "" # i.e. on-demand
|
493
|
+
spot_options[:max_price] = spot_price
|
521
494
|
end
|
522
|
-
end
|
523
495
|
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
end
|
529
|
-
server.volumes.each do |volume|
|
530
|
-
volume.create_tags(tags: tags)
|
531
|
-
end
|
532
|
-
end
|
533
|
-
end
|
496
|
+
instance_data[:instance_market_options] = {
|
497
|
+
market_type: "spot",
|
498
|
+
spot_options: spot_options,
|
499
|
+
}
|
534
500
|
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
(described_volume_count > 0) && (described_volume_count == ready_volume_count)
|
501
|
+
# The preferred way to create a spot instance is via request_spot_instances()
|
502
|
+
# However, it does not allow for tagging to occur at creation time.
|
503
|
+
# create_instances() allows creation of tagged spot instances, but does
|
504
|
+
# not retry if the price could not be satisfied immediately.
|
505
|
+
Retryable.retryable(
|
506
|
+
tries: config[:spot_wait] / config[:retryable_sleep],
|
507
|
+
sleep: lambda { |_n| config[:retryable_sleep] },
|
508
|
+
on: ::Aws::EC2::Errors::SpotMaxPriceTooLow
|
509
|
+
) do |retries|
|
510
|
+
c = retries * config[:retryable_sleep]
|
511
|
+
t = config[:spot_wait]
|
512
|
+
info "Waited #{c}/#{t}s for spot request to become fulfilled."
|
513
|
+
ec2.create_instance(instance_data)
|
549
514
|
end
|
550
515
|
end
|
551
516
|
|
@@ -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.1".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.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Fletcher Nichol
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-07-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: test-kitchen
|
@@ -30,34 +30,6 @@ dependencies:
|
|
30
30
|
- - "<"
|
31
31
|
- !ruby/object:Gem::Version
|
32
32
|
version: '3'
|
33
|
-
- !ruby/object:Gem::Dependency
|
34
|
-
name: excon
|
35
|
-
requirement: !ruby/object:Gem::Requirement
|
36
|
-
requirements:
|
37
|
-
- - ">="
|
38
|
-
- !ruby/object:Gem::Version
|
39
|
-
version: '0'
|
40
|
-
type: :runtime
|
41
|
-
prerelease: false
|
42
|
-
version_requirements: !ruby/object:Gem::Requirement
|
43
|
-
requirements:
|
44
|
-
- - ">="
|
45
|
-
- !ruby/object:Gem::Version
|
46
|
-
version: '0'
|
47
|
-
- !ruby/object:Gem::Dependency
|
48
|
-
name: multi_json
|
49
|
-
requirement: !ruby/object:Gem::Requirement
|
50
|
-
requirements:
|
51
|
-
- - ">="
|
52
|
-
- !ruby/object:Gem::Version
|
53
|
-
version: '0'
|
54
|
-
type: :runtime
|
55
|
-
prerelease: false
|
56
|
-
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
requirements:
|
58
|
-
- - ">="
|
59
|
-
- !ruby/object:Gem::Version
|
60
|
-
version: '0'
|
61
33
|
- !ruby/object:Gem::Dependency
|
62
34
|
name: aws-sdk-ec2
|
63
35
|
requirement: !ruby/object:Gem::Requirement
|
@@ -134,20 +106,6 @@ dependencies:
|
|
134
106
|
- - "~>"
|
135
107
|
- !ruby/object:Gem::Version
|
136
108
|
version: '0.6'
|
137
|
-
- !ruby/object:Gem::Dependency
|
138
|
-
name: simplecov
|
139
|
-
requirement: !ruby/object:Gem::Requirement
|
140
|
-
requirements:
|
141
|
-
- - "~>"
|
142
|
-
- !ruby/object:Gem::Version
|
143
|
-
version: '0.7'
|
144
|
-
type: :development
|
145
|
-
prerelease: false
|
146
|
-
version_requirements: !ruby/object:Gem::Requirement
|
147
|
-
requirements:
|
148
|
-
- - "~>"
|
149
|
-
- !ruby/object:Gem::Version
|
150
|
-
version: '0.7'
|
151
109
|
- !ruby/object:Gem::Dependency
|
152
110
|
name: yard
|
153
111
|
requirement: !ruby/object:Gem::Requirement
|
@@ -168,14 +126,14 @@ dependencies:
|
|
168
126
|
requirements:
|
169
127
|
- - '='
|
170
128
|
- !ruby/object:Gem::Version
|
171
|
-
version:
|
129
|
+
version: 1.1.2
|
172
130
|
type: :development
|
173
131
|
prerelease: false
|
174
132
|
version_requirements: !ruby/object:Gem::Requirement
|
175
133
|
requirements:
|
176
134
|
- - '='
|
177
135
|
- !ruby/object:Gem::Version
|
178
|
-
version:
|
136
|
+
version: 1.1.2
|
179
137
|
- !ruby/object:Gem::Dependency
|
180
138
|
name: climate_control
|
181
139
|
requirement: !ruby/object:Gem::Requirement
|
@@ -224,14 +182,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
224
182
|
requirements:
|
225
183
|
- - ">="
|
226
184
|
- !ruby/object:Gem::Version
|
227
|
-
version: '2.
|
185
|
+
version: '2.4'
|
228
186
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
229
187
|
requirements:
|
230
188
|
- - ">="
|
231
189
|
- !ruby/object:Gem::Version
|
232
190
|
version: '0'
|
233
191
|
requirements: []
|
234
|
-
rubygems_version: 3.
|
192
|
+
rubygems_version: 3.1.2
|
235
193
|
signing_key:
|
236
194
|
specification_version: 4
|
237
195
|
summary: A Test Kitchen Driver for Amazon EC2
|