kitchen-ec2 3.22.10 → 3.23.1
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
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4b31b976c77faa84d3828219b396b07d52790a806d0b2a0fc72b95f8dabbe548
|
|
4
|
+
data.tar.gz: 52cb6998a147c6ca43e638f80a16f3b461f3ed25d7999695c42197a1900c34e1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0d57aa3da2611170b0e00e140e9d671c1a7585048020da316c1194d238e9c3fd41ef4ffc62ed1e4375d1862983220cd6c67e48ca25f98777adc677e0d6987f87
|
|
7
|
+
data.tar.gz: 68faeb3e26106d8df47a4896b7d6f1ef18c3c30cbbfd2d12e1cac6dcd2dddacd208f60d92493647ec19fba347e50f14691c279ad33999bf109a5ca949817e7cc
|
|
@@ -88,7 +88,7 @@ module Kitchen
|
|
|
88
88
|
|
|
89
89
|
if config[:security_group_ids].nil? && config[:security_group_filter]
|
|
90
90
|
# => Grab the VPC in the case a Subnet ID rather than Filter was set
|
|
91
|
-
vpc_id ||= client
|
|
91
|
+
vpc_id ||= security_group_search_vpc_id(client)
|
|
92
92
|
security_groups = []
|
|
93
93
|
filters = [config[:security_group_filter]].flatten
|
|
94
94
|
filters.each do |sg_filter|
|
|
@@ -112,7 +112,10 @@ module Kitchen
|
|
|
112
112
|
"#{sg_filter.inspect} has neither."
|
|
113
113
|
end
|
|
114
114
|
|
|
115
|
-
|
|
115
|
+
# Only when a VPC is known. A name or tag has already narrowed the
|
|
116
|
+
# search, so leaving this off is not the unfiltered request the
|
|
117
|
+
# check above exists to prevent.
|
|
118
|
+
criteria << { name: "vpc-id", values: [vpc_id] } if vpc_id
|
|
116
119
|
|
|
117
120
|
security_group = client.describe_security_groups(filters: criteria).security_groups
|
|
118
121
|
|
|
@@ -243,6 +246,46 @@ module Kitchen
|
|
|
243
246
|
i
|
|
244
247
|
end
|
|
245
248
|
|
|
249
|
+
# The VPC to look for security groups in.
|
|
250
|
+
#
|
|
251
|
+
# Security group names are unique only within a VPC, so the search is
|
|
252
|
+
# scoped to the VPC the instance will launch into. Which VPC that is
|
|
253
|
+
# depends on how the subnet was chosen:
|
|
254
|
+
#
|
|
255
|
+
# - a named `subnet_id` decides it, so the subnet is described for it
|
|
256
|
+
# - no subnet at all means EC2 launches into the account's default VPC,
|
|
257
|
+
# so that is what gets searched
|
|
258
|
+
#
|
|
259
|
+
# The second case used to describe a subnet with an ID of nil and then
|
|
260
|
+
# read `vpc_id` off the empty result, so a `security_group_filter` on
|
|
261
|
+
# its own -- a documented combination, and the natural one in a default
|
|
262
|
+
# VPC account -- died with `undefined method 'vpc_id' for nil` before
|
|
263
|
+
# anything was launched.
|
|
264
|
+
#
|
|
265
|
+
# An account with no default VPC returns nil, and the caller then
|
|
266
|
+
# searches on the name or tag alone.
|
|
267
|
+
#
|
|
268
|
+
# @param client [Aws::EC2::Client] the client to query with
|
|
269
|
+
# @return [String, nil] the VPC ID, or nil when there is no default VPC
|
|
270
|
+
# @raise [RuntimeError] when a named subnet does not exist, which would
|
|
271
|
+
# otherwise surface as the same nil dereference
|
|
272
|
+
def security_group_search_vpc_id(client)
|
|
273
|
+
unless config[:subnet_id]
|
|
274
|
+
default_vpc = client.describe_vpcs(
|
|
275
|
+
filters: [{ name: "isDefault", values: %w{true} }]
|
|
276
|
+
).vpcs.first
|
|
277
|
+
|
|
278
|
+
return default_vpc&.vpc_id
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
subnet = client.describe_subnets(subnet_ids: [config[:subnet_id]]).subnets.first
|
|
282
|
+
unless subnet
|
|
283
|
+
raise "Subnet #{config[:subnet_id]} not found while resolving security_group_filter."
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
subnet.vpc_id
|
|
287
|
+
end
|
|
288
|
+
|
|
246
289
|
# The user data script, base64 encoded as EC2 requires.
|
|
247
290
|
#
|
|
248
291
|
# The configured value is treated as a file path when it names an
|
|
@@ -34,6 +34,24 @@ module Kitchen
|
|
|
34
34
|
"ec2-user"
|
|
35
35
|
end
|
|
36
36
|
|
|
37
|
+
# The AWS account Amazon publishes its macOS AMIs under.
|
|
38
|
+
#
|
|
39
|
+
# @return [String]
|
|
40
|
+
MACOS_OWNER_ID = "628277914472".freeze
|
|
41
|
+
|
|
42
|
+
# EC2's architecture values for Mac instances, keyed by the name the
|
|
43
|
+
# platform string uses.
|
|
44
|
+
#
|
|
45
|
+
# EC2 reports a Mac image's architecture as "x86_64_mac" or
|
|
46
|
+
# "arm64_mac", never the bare "x86_64" or "arm64" every other
|
|
47
|
+
# platform uses, so an unmapped value matches nothing at all.
|
|
48
|
+
#
|
|
49
|
+
# @return [Hash{String => String}]
|
|
50
|
+
MAC_ARCHITECTURES = {
|
|
51
|
+
"arm64" => "arm64_mac",
|
|
52
|
+
"x86_64" => "x86_64_mac",
|
|
53
|
+
}.freeze
|
|
54
|
+
|
|
37
55
|
# EC2 image filters that select Amazon's macOS AMIs, which run only on dedicated Mac hosts.
|
|
38
56
|
#
|
|
39
57
|
# A filter is added for {StandardPlatform#architecture} only when one was
|
|
@@ -44,11 +62,12 @@ module Kitchen
|
|
|
44
62
|
# @see StandardPlatform#find_image
|
|
45
63
|
def image_search
|
|
46
64
|
search = {
|
|
47
|
-
"owner-id" =>
|
|
65
|
+
"owner-id" => MACOS_OWNER_ID,
|
|
48
66
|
"name" => version ? "amzn-ec2-macos-#{version}*" : "amzn-ec2-macos-*",
|
|
49
67
|
}
|
|
50
|
-
|
|
51
|
-
|
|
68
|
+
if architecture
|
|
69
|
+
search["architecture"] = MAC_ARCHITECTURES.fetch(architecture, architecture)
|
|
70
|
+
end
|
|
52
71
|
search
|
|
53
72
|
end
|
|
54
73
|
|
|
@@ -176,7 +176,7 @@ module Kitchen
|
|
|
176
176
|
# Detect platform from an image.
|
|
177
177
|
#
|
|
178
178
|
# @param driver [Kitchen::Driver::Ec2] The driver.
|
|
179
|
-
# @param image [Aws::
|
|
179
|
+
# @param image [Aws::EC2::Image] The EC2 Image object.
|
|
180
180
|
#
|
|
181
181
|
# @return [Kitchen::Driver::Aws::StandardPlatform]
|
|
182
182
|
#
|
|
@@ -223,9 +223,9 @@ module Kitchen
|
|
|
223
223
|
# Used by the default find_image. The default version calls platform_from_image()
|
|
224
224
|
# on each image, and interprets the versions as floats (7 < 7.1 < 8).
|
|
225
225
|
#
|
|
226
|
-
# @param images [Array
|
|
226
|
+
# @param images [Array<Aws::EC2::Image>] The list of images to sort
|
|
227
227
|
#
|
|
228
|
-
# @return [Array
|
|
228
|
+
# @return [Array<Aws::EC2::Image>] A sorted list.
|
|
229
229
|
#
|
|
230
230
|
def sort_by_version(images)
|
|
231
231
|
# 7.1 -> [ img1, img2, img3 ]
|
|
@@ -246,6 +246,7 @@ module Kitchen
|
|
|
246
246
|
# preferences.
|
|
247
247
|
#
|
|
248
248
|
# @param images [Array<Aws::EC2::Image>] the images to reorder
|
|
249
|
+
# @param block [Proc] the predicate each image is partitioned by
|
|
249
250
|
# @yieldparam image [Aws::EC2::Image] an image to test
|
|
250
251
|
# @yieldreturn [Boolean] true when the image is preferred
|
|
251
252
|
# @return [Array<Aws::EC2::Image>] preferred images first
|
data/lib/kitchen/driver/ec2.rb
CHANGED
|
@@ -256,6 +256,72 @@ module Kitchen
|
|
|
256
256
|
|
|
257
257
|
# Create an EC2 instance and wait until it can be connected to.
|
|
258
258
|
#
|
|
259
|
+
# Configuration that cannot possibly work is rejected first, before
|
|
260
|
+
# anything billable is launched; {#launch_instance} does the real work.
|
|
261
|
+
#
|
|
262
|
+
# @param state [Hash] the instance state, updated in place with
|
|
263
|
+
# `:server_id`, `:hostname` and any auto-created credentials
|
|
264
|
+
# @return [void]
|
|
265
|
+
# @raise [Kitchen::UserError] when the platform is misconfigured such
|
|
266
|
+
# that the run could not succeed
|
|
267
|
+
def create(state)
|
|
268
|
+
return if state[:server_id]
|
|
269
|
+
|
|
270
|
+
# Deliberately checked here rather than inside #launch_instance: that
|
|
271
|
+
# method rewrites every exception it sees into an "is this AMI available
|
|
272
|
+
# in this region" message, which would bury this one.
|
|
273
|
+
assert_powershell_shell_type!
|
|
274
|
+
|
|
275
|
+
launch_instance(state)
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
# Refuse to launch a Windows instance that would be driven with a Bourne
|
|
279
|
+
# shell type.
|
|
280
|
+
#
|
|
281
|
+
# Test Kitchen infers `shell_type` from the platform *name*, not from
|
|
282
|
+
# `os_type`, so a Windows platform named something that does not begin
|
|
283
|
+
# with "windows" silently ends up as a Bourne host. The provisioner then
|
|
284
|
+
# generates Bourne commands, WinRM executes them in PowerShell, and the
|
|
285
|
+
# run fails deep into converge with an error that points nowhere near the
|
|
286
|
+
# real cause -- typically a `New-Item` complaint that the sandbox
|
|
287
|
+
# directory already exists.
|
|
288
|
+
#
|
|
289
|
+
# Failing here costs the user nothing; letting it through costs them a
|
|
290
|
+
# billable instance and a confusing converge failure.
|
|
291
|
+
#
|
|
292
|
+
# @raise [Kitchen::UserError] when the platform is Windows but its shell
|
|
293
|
+
# type is not PowerShell
|
|
294
|
+
# @return [void]
|
|
295
|
+
# @see https://github.com/test-kitchen/kitchen-ec2/issues/621
|
|
296
|
+
def assert_powershell_shell_type!
|
|
297
|
+
return unless windows_os?
|
|
298
|
+
return if powershell_shell?
|
|
299
|
+
|
|
300
|
+
shell_type = instance.platform.respond_to?(:shell_type) ? instance.platform.shell_type : nil
|
|
301
|
+
|
|
302
|
+
raise Kitchen::UserError, <<~MESSAGE
|
|
303
|
+
Platform '#{instance.platform.name}' sets os_type 'windows' but its shell_type is '#{shell_type}'.
|
|
304
|
+
|
|
305
|
+
Test Kitchen infers shell_type from the platform name, so a Windows platform
|
|
306
|
+
whose name does not begin with 'windows' is treated as a Bourne shell host.
|
|
307
|
+
Provisioner commands would be generated as Bourne syntax and then executed by
|
|
308
|
+
PowerShell over WinRM, failing during converge with an unrelated error such as
|
|
309
|
+
'Cannot create ... because a file or directory with the same name already exists'.
|
|
310
|
+
|
|
311
|
+
Set shell_type explicitly on the platform:
|
|
312
|
+
|
|
313
|
+
platforms:
|
|
314
|
+
- name: #{instance.platform.name}
|
|
315
|
+
os_type: windows
|
|
316
|
+
shell_type: powershell
|
|
317
|
+
|
|
318
|
+
Renaming the platform to start with 'windows' also works, as Test Kitchen then
|
|
319
|
+
infers both os_type and shell_type from the name.
|
|
320
|
+
MESSAGE
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
# Request the instance and wait until it can be connected to.
|
|
324
|
+
#
|
|
259
325
|
# Auto-creates a security group and key pair when none were configured,
|
|
260
326
|
# allocates a dedicated host if `tenancy: host` requires one, requests
|
|
261
327
|
# either an on-demand or a spot instance, then waits for the instance to
|
|
@@ -270,9 +336,7 @@ module Kitchen
|
|
|
270
336
|
# @return [void]
|
|
271
337
|
# @raise [Kitchen::ActionFailed] wrapping whatever went wrong, after
|
|
272
338
|
# cleaning up
|
|
273
|
-
def
|
|
274
|
-
return if state[:server_id]
|
|
275
|
-
|
|
339
|
+
def launch_instance(state)
|
|
276
340
|
update_username(state)
|
|
277
341
|
|
|
278
342
|
info(Kitchen::Util.outdent!(<<-END)) unless config[:skip_cost_warning]
|
|
@@ -389,7 +453,10 @@ module Kitchen
|
|
|
389
453
|
# @see https://github.com/test-kitchen/kitchen-ec2/issues/606
|
|
390
454
|
def create_failure_message(error)
|
|
391
455
|
message = "Failed to create the EC2 instance: #{error.class}: #{error.message}"
|
|
392
|
-
|
|
456
|
+
# The hint names the image, so it has nothing to say when there is no
|
|
457
|
+
# image to name. Without this it rendered as "Check that image exists"
|
|
458
|
+
# on exactly the failure where no image was ever resolved.
|
|
459
|
+
return message unless config[:image_id] && image_related_error?(error)
|
|
393
460
|
|
|
394
461
|
"#{message} Check that image #{config[:image_id]} exists and is available " \
|
|
395
462
|
"in region #{config[:region]}."
|
|
@@ -397,14 +464,19 @@ module Kitchen
|
|
|
397
464
|
|
|
398
465
|
# Whether a failure is about the AMI rather than something else entirely.
|
|
399
466
|
#
|
|
400
|
-
# EC2 reports every image problem with a code beginning "InvalidAMI"
|
|
401
|
-
# message check
|
|
402
|
-
# plain strings with no code attached
|
|
467
|
+
# EC2 reports every image problem with a code beginning "InvalidAMI". The
|
|
468
|
+
# message check is for errors raised by the driver itself, which are
|
|
469
|
+
# plain strings with no code attached -- but it only applies to those,
|
|
470
|
+
# because plenty of AWS errors merely *mention* the AMI while being about
|
|
471
|
+
# something else. The clearest example is an instance type whose
|
|
472
|
+
# architecture does not match the image's: its message names the AMI
|
|
473
|
+
# twice, and the old check duly told the user to go and check whether an
|
|
474
|
+
# image that exists, exists.
|
|
403
475
|
#
|
|
404
476
|
# @param error [Exception] the underlying failure
|
|
405
477
|
# @return [Boolean]
|
|
406
478
|
def image_related_error?(error)
|
|
407
|
-
return
|
|
479
|
+
return error.code.to_s.start_with?("InvalidAMI") if error.respond_to?(:code)
|
|
408
480
|
|
|
409
481
|
error.message.to_s.match?(/\bAMI\b/i)
|
|
410
482
|
end
|
|
@@ -429,10 +501,17 @@ module Kitchen
|
|
|
429
501
|
warn("Received #{e}, instance was probably already destroyed. Ignoring")
|
|
430
502
|
end
|
|
431
503
|
end
|
|
432
|
-
#
|
|
433
|
-
#
|
|
434
|
-
#
|
|
435
|
-
|
|
504
|
+
# Two cleanups below cannot succeed while the instance is still
|
|
505
|
+
# shutting down, so either of them means waiting termination out:
|
|
506
|
+
# an auto-created security group cannot be deleted while an instance
|
|
507
|
+
# still references it, and a dedicated host goes on listing a
|
|
508
|
+
# terminating instance, which blocks its release.
|
|
509
|
+
#
|
|
510
|
+
# The host case used to be missing, so a run that supplied its own
|
|
511
|
+
# `security_group_ids` skipped the wait, found the host still
|
|
512
|
+
# occupied, and silently left it allocated and billing.
|
|
513
|
+
if (state[:auto_security_group_id] || state[:allocated_host_id]) &&
|
|
514
|
+
server && ec2.instance_exists?(state[:server_id])
|
|
436
515
|
wait_log = proc do |attempts|
|
|
437
516
|
c = attempts * config[:retryable_sleep]
|
|
438
517
|
t = config[:retryable_tries] * config[:retryable_sleep]
|
|
@@ -468,7 +547,73 @@ module Kitchen
|
|
|
468
547
|
return unless host_id
|
|
469
548
|
|
|
470
549
|
host = host_for_id(host_id)
|
|
471
|
-
|
|
550
|
+
# Already gone, or never usable: nothing to release either way.
|
|
551
|
+
return if host.nil? || host.state != "available"
|
|
552
|
+
|
|
553
|
+
unless host_unused?(host)
|
|
554
|
+
# Test Kitchen deletes the state file once destroy returns, taking
|
|
555
|
+
# the host ID with it, so there is no later run that could pick this
|
|
556
|
+
# up -- say so loudly and give the command to finish the job.
|
|
557
|
+
error("Dedicated host #{host_id} still has instances on it and was not released. " \
|
|
558
|
+
"A dedicated host bills from allocation until it is released. Release it with: " \
|
|
559
|
+
"aws ec2 release-hosts --region #{config[:region]} --host-ids #{host_id}")
|
|
560
|
+
return
|
|
561
|
+
end
|
|
562
|
+
|
|
563
|
+
deallocate_host(host_id)
|
|
564
|
+
end
|
|
565
|
+
|
|
566
|
+
# EC2 instance states in which the instance still exists as a resource.
|
|
567
|
+
#
|
|
568
|
+
# "shutting-down" and "terminated" are left out deliberately. Neither can
|
|
569
|
+
# be brought back and neither leaves anything to destroy, so counting
|
|
570
|
+
# them as live would defeat the point of asking.
|
|
571
|
+
#
|
|
572
|
+
# @return [Array<String>]
|
|
573
|
+
LIVE_INSTANCE_STATES = %w{pending running stopping stopped}.freeze
|
|
574
|
+
|
|
575
|
+
# Whether the instance Test Kitchen recorded is still there.
|
|
576
|
+
#
|
|
577
|
+
# Answers `kitchen list --live` by asking EC2 rather than trusting the
|
|
578
|
+
# state file, which is the whole point: the state file records what Test
|
|
579
|
+
# Kitchen last did, not what survived. An instance terminated in the
|
|
580
|
+
# console, reaped by an account policy, or orphaned by a run that was
|
|
581
|
+
# killed mid-create all leave a state file claiming the instance exists.
|
|
582
|
+
#
|
|
583
|
+
# Kept to a single describe call, since `kitchen list --live` makes one
|
|
584
|
+
# of these per instance.
|
|
585
|
+
#
|
|
586
|
+
# @param state [Hash] the instance state
|
|
587
|
+
# @return [Hash] status data, normalized by Kitchen::Instance
|
|
588
|
+
# @see https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_InstanceState.html
|
|
589
|
+
def status(state)
|
|
590
|
+
unless state[:server_id]
|
|
591
|
+
return status_report(
|
|
592
|
+
live: false,
|
|
593
|
+
instance_state: "not_created",
|
|
594
|
+
message: "No EC2 instance has been created for this suite yet"
|
|
595
|
+
)
|
|
596
|
+
end
|
|
597
|
+
|
|
598
|
+
instance_state = ec2.get_instance(state[:server_id]).state.name
|
|
599
|
+
|
|
600
|
+
status_report(
|
|
601
|
+
live: LIVE_INSTANCE_STATES.include?(instance_state),
|
|
602
|
+
instance_state: instance_state,
|
|
603
|
+
resource_id: state[:server_id],
|
|
604
|
+
message: "EC2 instance #{state[:server_id]} is #{instance_state}"
|
|
605
|
+
)
|
|
606
|
+
rescue ::Aws::EC2::Errors::InvalidInstanceIDNotFound
|
|
607
|
+
# The reconciliation this check exists for: Test Kitchen still believes
|
|
608
|
+
# it has an instance, and EC2 has never heard of it.
|
|
609
|
+
status_report(
|
|
610
|
+
live: false,
|
|
611
|
+
instance_state: "not_found",
|
|
612
|
+
resource_id: state[:server_id],
|
|
613
|
+
message: "EC2 does not know instance #{state[:server_id]}. It was terminated " \
|
|
614
|
+
"outside Test Kitchen, or has aged out of EC2's terminated instance list. " \
|
|
615
|
+
"Run `kitchen destroy` to clear the stale state."
|
|
616
|
+
)
|
|
472
617
|
end
|
|
473
618
|
|
|
474
619
|
# The EC2 image this instance will be created from.
|
|
@@ -484,6 +629,14 @@ module Kitchen
|
|
|
484
629
|
@image = ec2.resource.image(config[:image_id])
|
|
485
630
|
show_chosen_image
|
|
486
631
|
|
|
632
|
+
elsif searched_for_image?
|
|
633
|
+
# A search ran and matched nothing. Saying "specify image_id or
|
|
634
|
+
# image_search" here sent people to set an option they had already
|
|
635
|
+
# set, or that the platform sets for them -- the real problem is
|
|
636
|
+
# that the filters matched no image in this region.
|
|
637
|
+
raise "The image search for #{desired_platform || instance.platform.name} matched no " \
|
|
638
|
+
"image in region #{config[:region]}. Set image_id to an AMI, or image_search to " \
|
|
639
|
+
"filters that match one."
|
|
487
640
|
else
|
|
488
641
|
raise "Neither image_id nor an image_search specified for instance #{instance.name}!" \
|
|
489
642
|
" Please specify one or the other."
|
|
@@ -492,16 +645,33 @@ module Kitchen
|
|
|
492
645
|
@image
|
|
493
646
|
end
|
|
494
647
|
|
|
648
|
+
# Whether an image search ran and came back empty.
|
|
649
|
+
#
|
|
650
|
+
# Distinguishes "there was nothing to search for" -- an unrecognized
|
|
651
|
+
# platform name and no `image_search` -- from "the search matched
|
|
652
|
+
# nothing", which are different mistakes with different fixes.
|
|
653
|
+
#
|
|
654
|
+
# @return [Boolean]
|
|
655
|
+
def searched_for_image?
|
|
656
|
+
!config[:image_search].nil? || !desired_platform.nil?
|
|
657
|
+
end
|
|
658
|
+
|
|
495
659
|
# The instance type to use when the user did not choose one.
|
|
496
660
|
#
|
|
661
|
+
# An instance type runs one processor architecture and EC2 rejects a
|
|
662
|
+
# RunInstances call pairing it with an image built for another, so the
|
|
663
|
+
# default has to follow the image: t4g is the Graviton counterpart of
|
|
664
|
+
# t3. Picking t3.micro for every HVM image made every arm64 platform --
|
|
665
|
+
# "ubuntu-24.04-arm64" and friends, an architecture this driver parses
|
|
666
|
+
# and searches for -- fail to launch outright.
|
|
667
|
+
#
|
|
497
668
|
# t3 instances require a hardware-virtualized image, so a paravirtual
|
|
498
669
|
# image falls back to the older t1 family.
|
|
499
670
|
#
|
|
500
|
-
# @return [String] a free-tier instance type
|
|
671
|
+
# @return [String] a free-tier instance type matching the image
|
|
501
672
|
def default_instance_type
|
|
502
673
|
@instance_type ||= if image && image.virtualization_type == "hvm"
|
|
503
|
-
|
|
504
|
-
"t3.micro"
|
|
674
|
+
hvm_default_instance_type
|
|
505
675
|
else
|
|
506
676
|
info("instance_type not specified. Using free tier t1.micro instance since" \
|
|
507
677
|
" image is paravirtual (pick an hvm image to use the superior t3.micro!) ...")
|
|
@@ -509,6 +679,25 @@ module Kitchen
|
|
|
509
679
|
end
|
|
510
680
|
end
|
|
511
681
|
|
|
682
|
+
# The free-tier instance type matching a hardware-virtualized image.
|
|
683
|
+
#
|
|
684
|
+
# Only arm64 is special-cased. EC2's Mac architectures ("arm64_mac" and
|
|
685
|
+
# "x86_64_mac") are deliberately not defaulted: they run only on
|
|
686
|
+
# dedicated Mac hosts, which carry a 24-hour minimum allocation, so
|
|
687
|
+
# guessing one would be an expensive surprise rather than a convenience.
|
|
688
|
+
#
|
|
689
|
+
# @return [String] the instance type to launch
|
|
690
|
+
def hvm_default_instance_type
|
|
691
|
+
if image.architecture == "arm64"
|
|
692
|
+
info("instance_type not specified. Using free tier t4g.micro instance" \
|
|
693
|
+
" since image is arm64 ...")
|
|
694
|
+
"t4g.micro"
|
|
695
|
+
else
|
|
696
|
+
info("instance_type not specified. Using free tier t3.micro instance ...")
|
|
697
|
+
"t3.micro"
|
|
698
|
+
end
|
|
699
|
+
end
|
|
700
|
+
|
|
512
701
|
# The platform detected from the image actually being used.
|
|
513
702
|
#
|
|
514
703
|
# This can differ from {#desired_platform}: the user asks for "ubuntu" and
|
|
@@ -820,6 +1009,7 @@ module Kitchen
|
|
|
820
1009
|
# @param server [Aws::EC2::Instance] the instance to wait on
|
|
821
1010
|
# @param state [Hash] the instance state
|
|
822
1011
|
# @param status_msg [String] what is being waited for, for log messages
|
|
1012
|
+
# @param block [Proc] the readiness check polled against the instance
|
|
823
1013
|
# @yieldparam aws_instance [Aws::EC2::Instance] the instance being polled
|
|
824
1014
|
# @yieldreturn [Boolean] true when the wait is over
|
|
825
1015
|
# @return [void]
|
|
@@ -1003,9 +1193,15 @@ module Kitchen
|
|
|
1003
1193
|
# so it does not matter which agent is installed. Only RAW disks are
|
|
1004
1194
|
# touched, so a volume that already carries a filesystem is never
|
|
1005
1195
|
# reformatted.
|
|
1196
|
+
#
|
|
1197
|
+
# GPT, not MBR: an MBR disk cannot address beyond 2 TiB, and
|
|
1198
|
+
# Initialize-Disk does not fail on a larger one -- it caps it, so a
|
|
1199
|
+
# 2600 GB volume came up as a 2 TiB filesystem with the remainder
|
|
1200
|
+
# unreachable and still billed. GPT is supported by every Windows
|
|
1201
|
+
# release this driver can launch.
|
|
1006
1202
|
"Initializing any uninitialized volumes" >> $logfile
|
|
1007
1203
|
Get-Disk | Where-Object PartitionStyle -eq 'RAW' |
|
|
1008
|
-
Initialize-Disk -PartitionStyle
|
|
1204
|
+
Initialize-Disk -PartitionStyle GPT -PassThru |
|
|
1009
1205
|
New-Partition -AssignDriveLetter -UseMaximumSize |
|
|
1010
1206
|
Format-Volume -FileSystem NTFS -Confirm:$false >> $logfile
|
|
1011
1207
|
|
|
@@ -1307,6 +1503,28 @@ module Kitchen
|
|
|
1307
1503
|
|
|
1308
1504
|
private
|
|
1309
1505
|
|
|
1506
|
+
# Build a status hash in the shape Kitchen::Instance normalizes.
|
|
1507
|
+
#
|
|
1508
|
+
# `checked_at` is stamped here rather than left out so that the timestamp
|
|
1509
|
+
# reflects when EC2 was actually asked, not when the answer was rendered.
|
|
1510
|
+
#
|
|
1511
|
+
# @param live [Boolean] whether the instance still exists
|
|
1512
|
+
# @param instance_state [String] the EC2 state name, or a driver-level
|
|
1513
|
+
# one such as "not_created" for the cases EC2 was never asked about
|
|
1514
|
+
# @param message [String] a human-readable explanation
|
|
1515
|
+
# @param resource_id [String, nil] the EC2 instance ID, when there is one
|
|
1516
|
+
# @return [Hash]
|
|
1517
|
+
def status_report(live:, instance_state:, message:, resource_id: nil)
|
|
1518
|
+
{
|
|
1519
|
+
live: live,
|
|
1520
|
+
state: instance_state,
|
|
1521
|
+
source: "driver",
|
|
1522
|
+
resource_id: resource_id,
|
|
1523
|
+
message: message,
|
|
1524
|
+
checked_at: Time.now.utc.iso8601,
|
|
1525
|
+
}
|
|
1526
|
+
end
|
|
1527
|
+
|
|
1310
1528
|
# Wrap the transport's `connection` method with Instance Connect setup.
|
|
1311
1529
|
#
|
|
1312
1530
|
# A pushed Instance Connect key expires after about a minute, so the key
|
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.23.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Test Kitchen Team
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-10-01 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: aws-sdk-ec2
|