kitchen-ec2 3.22.3 → 3.22.4
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 +23 -1
- data/lib/kitchen/driver/aws/dedicated_hosts.rb +74 -29
- data/lib/kitchen/driver/aws/instance_connect.rb +16 -0
- data/lib/kitchen/driver/aws/instance_generator.rb +42 -20
- data/lib/kitchen/driver/aws/ssm_session_manager.rb +20 -3
- data/lib/kitchen/driver/aws/standard_platform/alma.rb +21 -2
- data/lib/kitchen/driver/aws/standard_platform/amazon.rb +26 -3
- data/lib/kitchen/driver/aws/standard_platform/amazon2.rb +26 -3
- data/lib/kitchen/driver/aws/standard_platform/amazon2023.rb +26 -3
- data/lib/kitchen/driver/aws/standard_platform/centos.rb +35 -2
- data/lib/kitchen/driver/aws/standard_platform/debian.rb +44 -5
- data/lib/kitchen/driver/aws/standard_platform/fedora.rb +21 -2
- data/lib/kitchen/driver/aws/standard_platform/freebsd.rb +27 -2
- data/lib/kitchen/driver/aws/standard_platform/macos.rb +30 -4
- data/lib/kitchen/driver/aws/standard_platform/rhel.rb +40 -2
- data/lib/kitchen/driver/aws/standard_platform/rocky.rb +30 -3
- data/lib/kitchen/driver/aws/standard_platform/ubuntu.rb +21 -2
- data/lib/kitchen/driver/aws/standard_platform/windows.rb +67 -34
- data/lib/kitchen/driver/aws/standard_platform.rb +46 -2
- data/lib/kitchen/driver/ec2.rb +332 -10
- data/lib/kitchen/driver/ec2_version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8c45dbb3160767d4ce660a83da145699c8e29f5fbb93b9ccb052ee8c4b8e5eb1
|
|
4
|
+
data.tar.gz: 8da4c4fdcc43e66e5ae58f722397f8663470b7c34167c3d47ec64219ec99824d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2b035d3317d7134b04811773347768ba33dfd3713ea3726ab124e2bfbc11afa54a23f3bd18f38fc7d01db9b9dd7b8c7d49cfdc4f1e0835e41281f1c6af9d1b4d
|
|
7
|
+
data.tar.gz: eb00b8d53f41145b6d2deec25c0a840f45be3d5a605907c8f886d52448f667ebcd6496ad279a0f9e82b56938dd1ffbd9a036eb57161e7c3ebef310f883feab08
|
|
@@ -23,11 +23,26 @@ require "aws-sdk-core/instance_profile_credentials"
|
|
|
23
23
|
|
|
24
24
|
module Kitchen
|
|
25
25
|
module Driver
|
|
26
|
+
# Namespace for the driver's AWS-facing collaborators: the EC2 client
|
|
27
|
+
# wrapper, the RunInstances payload generator, the platform definitions and
|
|
28
|
+
# the Instance Connect and SSM Session Manager helpers.
|
|
26
29
|
class Aws
|
|
27
30
|
# A class for creating and managing the EC2 client connection
|
|
28
31
|
#
|
|
29
32
|
# @author Tyler Ball <tball@chef.io>
|
|
30
33
|
class Client
|
|
34
|
+
# Configure the AWS SDK for this driver's connection settings.
|
|
35
|
+
#
|
|
36
|
+
# These settings are applied to the SDK's process-wide configuration
|
|
37
|
+
# rather than held on this object, so clients built later pick them up.
|
|
38
|
+
# A nil retry limit is omitted rather than written, so that the SDK's
|
|
39
|
+
# own default survives.
|
|
40
|
+
#
|
|
41
|
+
# @param region [String] the AWS region, e.g. "us-west-2"
|
|
42
|
+
# @param profile_name [String] shared credentials profile to use
|
|
43
|
+
# @param http_proxy [String, nil] proxy URL, if any
|
|
44
|
+
# @param retry_limit [Integer, nil] SDK retry limit, or nil for the default
|
|
45
|
+
# @param ssl_verify_peer [Boolean] whether to verify TLS peers
|
|
31
46
|
def initialize(
|
|
32
47
|
region,
|
|
33
48
|
profile_name = "default",
|
|
@@ -73,15 +88,22 @@ module Kitchen
|
|
|
73
88
|
|
|
74
89
|
# check if instance exists, given an id
|
|
75
90
|
# @param id [String] aws instance id
|
|
76
|
-
# @return
|
|
91
|
+
# @return [Boolean]
|
|
77
92
|
def instance_exists?(id)
|
|
78
93
|
resource.instance(id).exists?
|
|
79
94
|
end
|
|
80
95
|
|
|
96
|
+
# The low-level EC2 client, for API calls with no resource equivalent.
|
|
97
|
+
#
|
|
98
|
+
# @return [Aws::EC2::Client]
|
|
81
99
|
def client
|
|
82
100
|
@client ||= ::Aws::EC2::Client.new
|
|
83
101
|
end
|
|
84
102
|
|
|
103
|
+
# The EC2 resource interface, for working with instances and images as
|
|
104
|
+
# objects rather than raw API responses.
|
|
105
|
+
#
|
|
106
|
+
# @return [Aws::EC2::Resource]
|
|
85
107
|
def resource
|
|
86
108
|
@resource ||= ::Aws::EC2::Resource.new
|
|
87
109
|
end
|
|
@@ -1,15 +1,34 @@
|
|
|
1
1
|
module Kitchen
|
|
2
2
|
module Driver
|
|
3
|
+
# Namespace for behavior mixed into {Kitchen::Driver::Ec2}.
|
|
3
4
|
module Mixins
|
|
5
|
+
# Allocation and release of EC2 Dedicated Hosts.
|
|
6
|
+
#
|
|
7
|
+
# A dedicated host is physical hardware reserved for one account, required
|
|
8
|
+
# for `tenancy: host` and for platforms such as macOS. Hosts are billed
|
|
9
|
+
# from allocation until release regardless of whether an instance is
|
|
10
|
+
# running on them, so both operations are gated behind explicit config and
|
|
11
|
+
# failures are fatal rather than warnings.
|
|
12
|
+
#
|
|
13
|
+
# Only hosts tagged `ManagedBy: Test Kitchen` are ever considered, so a
|
|
14
|
+
# user's own dedicated hosts are never allocated to or released.
|
|
15
|
+
#
|
|
16
|
+
# This module expects its includer to provide `config`, `ec2` and the
|
|
17
|
+
# Test Kitchen logging methods; it is mixed into {Kitchen::Driver::Ec2}.
|
|
4
18
|
module DedicatedHosts
|
|
5
|
-
#
|
|
6
|
-
#
|
|
19
|
+
# Whether any managed host has room for the configured instance type.
|
|
20
|
+
#
|
|
21
|
+
# @return [Boolean]
|
|
7
22
|
def host_available?
|
|
8
23
|
!hosts_with_capacity.empty?
|
|
9
24
|
end
|
|
10
25
|
|
|
11
|
-
#
|
|
12
|
-
#
|
|
26
|
+
# Managed hosts with room for the configured instance type.
|
|
27
|
+
#
|
|
28
|
+
# T-family hosts report no capacity information and may be
|
|
29
|
+
# overprovisioned, so a host with no capacity block counts as available.
|
|
30
|
+
#
|
|
31
|
+
# @return [Array<Aws::EC2::Types::Host>]
|
|
13
32
|
def hosts_with_capacity
|
|
14
33
|
hosts_managed.select do |host|
|
|
15
34
|
# T-instance hosts do not report available capacity and can be overprovisioned
|
|
@@ -18,27 +37,38 @@ module Kitchen
|
|
|
18
37
|
else
|
|
19
38
|
instance_capacity = host.available_capacity.available_instance_capacity
|
|
20
39
|
capacity_for_type = instance_capacity.detect { |cap| cap.instance_type == config[:instance_type] }
|
|
21
|
-
|
|
40
|
+
# A host that lists no capacity for this instance type cannot run
|
|
41
|
+
# one, so treat a missing entry the same as zero rather than
|
|
42
|
+
# raising on it.
|
|
43
|
+
!capacity_for_type.nil? && capacity_for_type.available_capacity > 0
|
|
22
44
|
end
|
|
23
45
|
end
|
|
24
46
|
end
|
|
25
47
|
|
|
26
|
-
#
|
|
27
|
-
#
|
|
28
|
-
# @
|
|
48
|
+
# Whether a host has no instances running on it.
|
|
49
|
+
#
|
|
50
|
+
# @param host [Aws::EC2::Types::Host] the host to inspect
|
|
51
|
+
# @return [Boolean] true when the host can be released
|
|
29
52
|
def host_unused?(host)
|
|
30
53
|
host.instances.empty?
|
|
31
54
|
end
|
|
32
55
|
|
|
33
|
-
#
|
|
34
|
-
#
|
|
35
|
-
# @
|
|
56
|
+
# Look a dedicated host up by ID.
|
|
57
|
+
#
|
|
58
|
+
# @param host_id [String] the host ID, e.g. "h-0123456789abcdef0"
|
|
59
|
+
# @return [Aws::EC2::Types::Host, nil] the host, or nil when EC2 does
|
|
60
|
+
# not know it
|
|
36
61
|
def host_for_id(host_id)
|
|
37
|
-
ec2.client.describe_hosts(host_ids: [host_id])
|
|
62
|
+
ec2.client.describe_hosts(host_ids: [host_id]).hosts.first
|
|
38
63
|
end
|
|
39
64
|
|
|
40
|
-
#
|
|
41
|
-
#
|
|
65
|
+
# Available dedicated hosts that Test Kitchen allocated.
|
|
66
|
+
#
|
|
67
|
+
# Filtered on the `ManagedBy` tag so that hosts belonging to the user are
|
|
68
|
+
# never touched, and on state so that hosts still being provisioned or
|
|
69
|
+
# already released are ignored.
|
|
70
|
+
#
|
|
71
|
+
# @return [Array<Aws::EC2::Types::Host>]
|
|
42
72
|
def hosts_managed
|
|
43
73
|
response = ec2.client.describe_hosts(
|
|
44
74
|
filter: [
|
|
@@ -49,8 +79,16 @@ module Kitchen
|
|
|
49
79
|
response.hosts.select { |host| host.state == "available" }
|
|
50
80
|
end
|
|
51
81
|
|
|
52
|
-
#
|
|
53
|
-
#
|
|
82
|
+
# Allocate a new dedicated host for the configured instance type.
|
|
83
|
+
#
|
|
84
|
+
# A `.metal` size occupies a whole host, so it is allocated for that
|
|
85
|
+
# exact type; every other size can share a host, so the whole instance
|
|
86
|
+
# family is allocated and EC2 places instances within it.
|
|
87
|
+
#
|
|
88
|
+
# @return [String] the new host's ID
|
|
89
|
+
# @note Terminates the process with `exit!` when allocation is not
|
|
90
|
+
# enabled or no availability zone is configured, since an allocated
|
|
91
|
+
# host costs money whether or not it is used.
|
|
54
92
|
def allocate_host
|
|
55
93
|
unless allow_allocate_host?
|
|
56
94
|
warn "ERROR: Attempted to allocate dedicated host but need environment variable TK_ALLOCATE_DEDICATED_HOST to be set"
|
|
@@ -91,9 +129,12 @@ module Kitchen
|
|
|
91
129
|
response.host_ids.first
|
|
92
130
|
end
|
|
93
131
|
|
|
94
|
-
#
|
|
95
|
-
#
|
|
96
|
-
# @
|
|
132
|
+
# Release a dedicated host.
|
|
133
|
+
#
|
|
134
|
+
# @param host_id [String] the host to release
|
|
135
|
+
# @return [nil] when the host was released successfully
|
|
136
|
+
# @note Terminates the process with `exit!` when the release fails, as a
|
|
137
|
+
# host that stays allocated keeps accruing charges silently.
|
|
97
138
|
def deallocate_host(host_id)
|
|
98
139
|
info("Deallocating dedicated host #{host_id}")
|
|
99
140
|
|
|
@@ -104,28 +145,32 @@ module Kitchen
|
|
|
104
145
|
exit!
|
|
105
146
|
end
|
|
106
147
|
|
|
107
|
-
#
|
|
108
|
-
#
|
|
109
|
-
# @
|
|
148
|
+
# The family part of an instance type.
|
|
149
|
+
#
|
|
150
|
+
# @param instance_type [String] a type in "family.size" form, e.g. "m5.large"
|
|
151
|
+
# @return [String] the family, e.g. "m5"
|
|
110
152
|
def instance_family_from_type(instance_type)
|
|
111
153
|
instance_type.split(".").first
|
|
112
154
|
end
|
|
113
155
|
|
|
114
|
-
#
|
|
115
|
-
#
|
|
116
|
-
# @
|
|
156
|
+
# The size part of an instance type.
|
|
157
|
+
#
|
|
158
|
+
# @param instance_type [String] a type in "family.size" form, e.g. "m5.large"
|
|
159
|
+
# @return [String] the size, e.g. "large"
|
|
117
160
|
def instance_size_from_type(instance_type)
|
|
118
161
|
instance_type.split(".").last
|
|
119
162
|
end
|
|
120
163
|
|
|
121
|
-
#
|
|
122
|
-
#
|
|
164
|
+
# Whether the user has opted in to allocating dedicated hosts.
|
|
165
|
+
#
|
|
166
|
+
# @return [Boolean]
|
|
123
167
|
def allow_allocate_host?
|
|
124
168
|
config[:allocate_dedicated_host]
|
|
125
169
|
end
|
|
126
170
|
|
|
127
|
-
#
|
|
128
|
-
#
|
|
171
|
+
# Whether the user has opted in to releasing dedicated hosts.
|
|
172
|
+
#
|
|
173
|
+
# @return [Boolean]
|
|
129
174
|
def allow_deallocate_host?
|
|
130
175
|
config[:deallocate_dedicated_host]
|
|
131
176
|
end
|
|
@@ -19,13 +19,29 @@ require "aws-sdk-ec2instanceconnect"
|
|
|
19
19
|
module Kitchen
|
|
20
20
|
module Driver
|
|
21
21
|
class Aws
|
|
22
|
+
# Pushes short-lived SSH public keys to an instance using EC2 Instance
|
|
23
|
+
# Connect, so that a connection can be made without a long-lived key pair.
|
|
24
|
+
#
|
|
25
|
+
# A pushed key is accepted for roughly sixty seconds, so it is sent again
|
|
26
|
+
# before each connection rather than once at create time.
|
|
22
27
|
class InstanceConnect
|
|
28
|
+
# @param config [Hash] the driver config
|
|
29
|
+
# @param logger [Kitchen::Logger] the logger to report through
|
|
23
30
|
def initialize(config, logger)
|
|
24
31
|
@config = config
|
|
25
32
|
@logger = logger
|
|
26
33
|
@client = ::Aws::EC2InstanceConnect::Client.new(region: config[:region])
|
|
27
34
|
end
|
|
28
35
|
|
|
36
|
+
# Push an SSH public key to an instance for a given user.
|
|
37
|
+
#
|
|
38
|
+
# @param instance_id [String] the target instance, e.g. "i-0123abcd"
|
|
39
|
+
# @param username [String] the OS account to authorize the key for
|
|
40
|
+
# @param public_key [String] the OpenSSH-format public key
|
|
41
|
+
# @raise [Aws::EC2InstanceConnect::Errors::ServiceError] when the key is
|
|
42
|
+
# rejected; there is no usable connection in that case, so the error
|
|
43
|
+
# is not swallowed
|
|
44
|
+
# @return [void]
|
|
29
45
|
def send_ssh_public_key(instance_id, username, public_key)
|
|
30
46
|
@logger.info("Sending SSH public key to instance #{instance_id} for user #{username}")
|
|
31
47
|
|
|
@@ -26,18 +26,41 @@ module Kitchen
|
|
|
26
26
|
#
|
|
27
27
|
# @author Tyler Ball <tball@chef.io>
|
|
28
28
|
class InstanceGenerator
|
|
29
|
-
|
|
29
|
+
# @return [Hash] the driver config the payload is built from
|
|
30
|
+
attr_reader :config
|
|
30
31
|
|
|
32
|
+
# @return [Kitchen::Driver::Aws::Client] the driver's EC2 client wrapper
|
|
33
|
+
attr_reader :ec2
|
|
34
|
+
|
|
35
|
+
# @return [Kitchen::Logger] the logger to report through
|
|
36
|
+
attr_reader :logger
|
|
37
|
+
|
|
38
|
+
# @param config [Hash] the driver config
|
|
39
|
+
# @param ec2 [Kitchen::Driver::Aws::Client] the driver's EC2 client wrapper
|
|
40
|
+
# @param logger [Kitchen::Logger] the logger to report through
|
|
31
41
|
def initialize(config, ec2, logger)
|
|
32
42
|
@config = config
|
|
33
43
|
@ec2 = ec2
|
|
34
44
|
@logger = logger
|
|
35
45
|
end
|
|
36
46
|
|
|
37
|
-
#
|
|
38
|
-
#
|
|
39
|
-
# Some fields
|
|
40
|
-
#
|
|
47
|
+
# Build the RunInstances payload from the driver config.
|
|
48
|
+
#
|
|
49
|
+
# Some EC2 fields accept an explicit nil and others must be omitted
|
|
50
|
+
# entirely, so optional settings are added conditionally rather than
|
|
51
|
+
# always being present with a nil value.
|
|
52
|
+
#
|
|
53
|
+
# Two lookups happen here as a side effect, because both need to resolve
|
|
54
|
+
# before the payload can be built: a subnet is resolved from
|
|
55
|
+
# `subnet_filter` (and written back into the config), and security
|
|
56
|
+
# groups are resolved from `security_group_filter` within that subnet's
|
|
57
|
+
# VPC. Both are skipped when the corresponding ID is already set.
|
|
58
|
+
#
|
|
59
|
+
# @return [Hash] parameters for `Aws::EC2::Resource#create_instances`
|
|
60
|
+
# @raise [RuntimeError] when a subnet or security group filter matches
|
|
61
|
+
# nothing, since launching into an unintended network is worse than
|
|
62
|
+
# failing
|
|
63
|
+
# @see https://docs.aws.amazon.com/sdkforruby/api/Aws/EC2/Resource.html#create_instances-instance_method
|
|
41
64
|
def ec2_instance_data
|
|
42
65
|
# Support for looking up security group id and subnet id using tags.
|
|
43
66
|
vpc_id = nil
|
|
@@ -130,21 +153,6 @@ module Kitchen
|
|
|
130
153
|
i[:tag_specifications] = [instance_tag_spec, volume_tag_spec]
|
|
131
154
|
end
|
|
132
155
|
|
|
133
|
-
availability_zone = config[:availability_zone]
|
|
134
|
-
if availability_zone
|
|
135
|
-
if /^[a-z]$/i.match?(availability_zone)
|
|
136
|
-
availability_zone = "#{config[:region]}#{availability_zone}"
|
|
137
|
-
end
|
|
138
|
-
i[:placement] = { availability_zone: availability_zone.downcase }
|
|
139
|
-
end
|
|
140
|
-
tenancy = config[:tenancy]
|
|
141
|
-
if tenancy
|
|
142
|
-
if i.key?(:placement)
|
|
143
|
-
i[:placement][:tenancy] = tenancy
|
|
144
|
-
else
|
|
145
|
-
i[:placement] = { tenancy: }
|
|
146
|
-
end
|
|
147
|
-
end
|
|
148
156
|
unless config[:block_device_mappings].nil? || config[:block_device_mappings].empty?
|
|
149
157
|
i[:block_device_mappings] = config[:block_device_mappings]
|
|
150
158
|
end
|
|
@@ -177,6 +185,8 @@ module Kitchen
|
|
|
177
185
|
i[:network_interfaces][0][:ipv_6_address_count] = 1
|
|
178
186
|
end
|
|
179
187
|
end
|
|
188
|
+
# A bare zone letter is a shorthand for that zone within the
|
|
189
|
+
# configured region, so "b" in us-west-2 becomes "us-west-2b".
|
|
180
190
|
availability_zone = config[:availability_zone]
|
|
181
191
|
if availability_zone
|
|
182
192
|
if /^[a-z]$/i.match?(availability_zone)
|
|
@@ -236,6 +246,18 @@ module Kitchen
|
|
|
236
246
|
i
|
|
237
247
|
end
|
|
238
248
|
|
|
249
|
+
# The user data script, base64 encoded as EC2 requires.
|
|
250
|
+
#
|
|
251
|
+
# The configured value is treated as a file path when it names an
|
|
252
|
+
# existing file, and as inline script content otherwise. Content
|
|
253
|
+
# containing a null byte is always treated as inline, both because a
|
|
254
|
+
# path cannot contain one and because `File.file?` would raise on it.
|
|
255
|
+
#
|
|
256
|
+
# The result is memoized: the file is read once per driver, not once per
|
|
257
|
+
# call.
|
|
258
|
+
#
|
|
259
|
+
# @return [String, nil] base64 encoded user data, or nil when none is
|
|
260
|
+
# configured
|
|
239
261
|
def prepared_user_data
|
|
240
262
|
# If user_data is a file reference, lets read it as such
|
|
241
263
|
return nil if config[:user_data].nil?
|
|
@@ -23,6 +23,8 @@ module Kitchen
|
|
|
23
23
|
class Aws
|
|
24
24
|
# Manages AWS Systems Manager Session Manager connections for Test Kitchen
|
|
25
25
|
class SsmSessionManager
|
|
26
|
+
# @param config [Hash] the driver config
|
|
27
|
+
# @param logger [Kitchen::Logger] the logger to report through
|
|
26
28
|
def initialize(config, logger)
|
|
27
29
|
@config = config
|
|
28
30
|
@logger = logger
|
|
@@ -32,7 +34,13 @@ module Kitchen
|
|
|
32
34
|
)
|
|
33
35
|
end
|
|
34
36
|
|
|
35
|
-
#
|
|
37
|
+
# Whether the SSM agent on an instance has checked in and is reachable.
|
|
38
|
+
#
|
|
39
|
+
# Polled while an instance boots, so an API error is reported as "not
|
|
40
|
+
# ready" rather than raised.
|
|
41
|
+
#
|
|
42
|
+
# @param instance_id [String] the instance to check
|
|
43
|
+
# @return [Boolean] true when the agent is registered and online
|
|
36
44
|
def ssm_agent_available?(instance_id)
|
|
37
45
|
@logger.debug("Checking if SSM agent is available on instance #{instance_id}")
|
|
38
46
|
|
|
@@ -62,7 +70,12 @@ module Kitchen
|
|
|
62
70
|
end
|
|
63
71
|
end
|
|
64
72
|
|
|
65
|
-
#
|
|
73
|
+
# Whether the AWS CLI Session Manager plugin is installed locally.
|
|
74
|
+
#
|
|
75
|
+
# The plugin is a separate download from the AWS CLI itself and is
|
|
76
|
+
# required to open a session.
|
|
77
|
+
#
|
|
78
|
+
# @return [Boolean] true when the plugin responds to `--version`
|
|
66
79
|
def session_manager_plugin_installed?
|
|
67
80
|
_output, status = Open3.capture2e("session-manager-plugin", "--version")
|
|
68
81
|
installed = status.success?
|
|
@@ -75,7 +88,11 @@ module Kitchen
|
|
|
75
88
|
end
|
|
76
89
|
|
|
77
90
|
installed
|
|
78
|
-
|
|
91
|
+
# ::StandardError, not StandardError: this file is nested inside
|
|
92
|
+
# `module Kitchen`, which defines Kitchen::StandardError. An unqualified
|
|
93
|
+
# constant resolves to that one, which would let the Errno::ENOENT
|
|
94
|
+
# raised by a missing plugin escape the check meant to detect it.
|
|
95
|
+
rescue ::StandardError => e
|
|
79
96
|
@logger.warn("Error checking for session-manager-plugin: #{e.message}")
|
|
80
97
|
false
|
|
81
98
|
end
|
|
@@ -24,12 +24,23 @@ module Kitchen
|
|
|
24
24
|
StandardPlatform.platforms["alma"] = self
|
|
25
25
|
StandardPlatform.platforms["almalinux"] = self
|
|
26
26
|
|
|
27
|
-
#
|
|
28
|
-
#
|
|
27
|
+
# The account EC2 creates on this platform's official AMIs.
|
|
28
|
+
#
|
|
29
|
+
# Used as the SSH username when the transport does not specify one.
|
|
30
|
+
#
|
|
31
|
+
# @return [String] the default SSH username
|
|
29
32
|
def username
|
|
30
33
|
"ec2-user"
|
|
31
34
|
end
|
|
32
35
|
|
|
36
|
+
# EC2 image filters that select AlmaLinux OS images published by the AlmaLinux project.
|
|
37
|
+
#
|
|
38
|
+
# A filter is added for {StandardPlatform#architecture} only when one was
|
|
39
|
+
# requested, so that an unspecified architecture matches any of them.
|
|
40
|
+
#
|
|
41
|
+
# @return [Hash{String => String, Array<String>}] filter name to the value
|
|
42
|
+
# or values it must match
|
|
43
|
+
# @see StandardPlatform#find_image
|
|
33
44
|
def image_search
|
|
34
45
|
search = {
|
|
35
46
|
"owner-id" => "764336703387",
|
|
@@ -39,6 +50,14 @@ module Kitchen
|
|
|
39
50
|
search
|
|
40
51
|
end
|
|
41
52
|
|
|
53
|
+
# Detect this platform from an EC2 image.
|
|
54
|
+
#
|
|
55
|
+
# Matching is done on the image name, which is the only reliable signal
|
|
56
|
+
# EC2 exposes about what an AMI actually contains.
|
|
57
|
+
#
|
|
58
|
+
# @param driver [Kitchen::Driver::Ec2] the driver requesting detection
|
|
59
|
+
# @param image [Aws::EC2::Image] the image to inspect
|
|
60
|
+
# @return [Alma, nil] a platform when the image is AlmaLinux, otherwise nil
|
|
42
61
|
def self.from_image(driver, image)
|
|
43
62
|
return unless /AlmaLinux OS/i.match?(image.name)
|
|
44
63
|
|
|
@@ -23,12 +23,23 @@ module Kitchen
|
|
|
23
23
|
class Amazon < StandardPlatform
|
|
24
24
|
StandardPlatform.platforms["amazon"] = self
|
|
25
25
|
|
|
26
|
-
#
|
|
27
|
-
#
|
|
26
|
+
# The account EC2 creates on this platform's official AMIs.
|
|
27
|
+
#
|
|
28
|
+
# Used as the SSH username when the transport does not specify one.
|
|
29
|
+
#
|
|
30
|
+
# @return [String] the default SSH username
|
|
28
31
|
def username
|
|
29
32
|
"ec2-user"
|
|
30
33
|
end
|
|
31
34
|
|
|
35
|
+
# EC2 image filters that select the original Amazon Linux AMIs published by AWS.
|
|
36
|
+
#
|
|
37
|
+
# A filter is added for {StandardPlatform#architecture} only when one was
|
|
38
|
+
# requested, so that an unspecified architecture matches any of them.
|
|
39
|
+
#
|
|
40
|
+
# @return [Hash{String => String, Array<String>}] filter name to the value
|
|
41
|
+
# or values it must match
|
|
42
|
+
# @see StandardPlatform#find_image
|
|
32
43
|
def image_search
|
|
33
44
|
search = {
|
|
34
45
|
"owner-id" => "137112412989",
|
|
@@ -38,10 +49,22 @@ module Kitchen
|
|
|
38
49
|
search
|
|
39
50
|
end
|
|
40
51
|
|
|
52
|
+
# Detect this platform from an EC2 image.
|
|
53
|
+
#
|
|
54
|
+
# Matching is done on the image name, which is the only reliable signal
|
|
55
|
+
# EC2 exposes about what an AMI actually contains.
|
|
56
|
+
#
|
|
57
|
+
# @param driver [Kitchen::Driver::Ec2] the driver requesting detection
|
|
58
|
+
# @param image [Aws::EC2::Image] the image to inspect
|
|
59
|
+
# @return [Amazon, nil] a platform when the image is Amazon Linux, otherwise nil
|
|
41
60
|
def self.from_image(driver, image)
|
|
42
61
|
return unless /amzn-ami/i.match?(image.name)
|
|
43
62
|
|
|
44
|
-
|
|
63
|
+
# `(\.\d+)?`, not `(\.\d+[\.\d])?`: the character class matched the
|
|
64
|
+
# separator that follows the minor version, capturing it into the
|
|
65
|
+
# version string ("2018.03.") and failing outright when the minor
|
|
66
|
+
# version was followed by anything but a dot or digit.
|
|
67
|
+
image.name =~ /\b(\d+(\.\d+)?)/i
|
|
45
68
|
new(driver, "amazon", (Regexp.last_match || [])[1], image.architecture)
|
|
46
69
|
end
|
|
47
70
|
end
|
|
@@ -23,12 +23,23 @@ module Kitchen
|
|
|
23
23
|
class Amazon2 < StandardPlatform
|
|
24
24
|
StandardPlatform.platforms["amazon2"] = self
|
|
25
25
|
|
|
26
|
-
#
|
|
27
|
-
#
|
|
26
|
+
# The account EC2 creates on this platform's official AMIs.
|
|
27
|
+
#
|
|
28
|
+
# Used as the SSH username when the transport does not specify one.
|
|
29
|
+
#
|
|
30
|
+
# @return [String] the default SSH username
|
|
28
31
|
def username
|
|
29
32
|
"ec2-user"
|
|
30
33
|
end
|
|
31
34
|
|
|
35
|
+
# EC2 image filters that select Amazon Linux 2 AMIs published by AWS.
|
|
36
|
+
#
|
|
37
|
+
# A filter is added for {StandardPlatform#architecture} only when one was
|
|
38
|
+
# requested, so that an unspecified architecture matches any of them.
|
|
39
|
+
#
|
|
40
|
+
# @return [Hash{String => String, Array<String>}] filter name to the value
|
|
41
|
+
# or values it must match
|
|
42
|
+
# @see StandardPlatform#find_image
|
|
32
43
|
def image_search
|
|
33
44
|
search = {
|
|
34
45
|
"owner-id" => "137112412989",
|
|
@@ -38,10 +49,22 @@ module Kitchen
|
|
|
38
49
|
search
|
|
39
50
|
end
|
|
40
51
|
|
|
52
|
+
# Detect this platform from an EC2 image.
|
|
53
|
+
#
|
|
54
|
+
# Matching is done on the image name, which is the only reliable signal
|
|
55
|
+
# EC2 exposes about what an AMI actually contains.
|
|
56
|
+
#
|
|
57
|
+
# @param driver [Kitchen::Driver::Ec2] the driver requesting detection
|
|
58
|
+
# @param image [Aws::EC2::Image] the image to inspect
|
|
59
|
+
# @return [Amazon2, nil] a platform when the image is Amazon Linux 2, otherwise nil
|
|
41
60
|
def self.from_image(driver, image)
|
|
42
61
|
return unless /amzn2-ami/i.match?(image.name)
|
|
43
62
|
|
|
44
|
-
|
|
63
|
+
# `(\.\d+)?`, not `(\.\d+[\.\d])?`: the character class matched the
|
|
64
|
+
# separator that follows the minor version, capturing it into the
|
|
65
|
+
# version string ("2018.03.") and failing outright when the minor
|
|
66
|
+
# version was followed by anything but a dot or digit.
|
|
67
|
+
image.name =~ /\b(\d+(\.\d+)?)/i
|
|
45
68
|
new(driver, "amazon2", (Regexp.last_match || [])[1], image.architecture)
|
|
46
69
|
end
|
|
47
70
|
end
|
|
@@ -23,12 +23,23 @@ module Kitchen
|
|
|
23
23
|
class Amazon2023 < StandardPlatform
|
|
24
24
|
StandardPlatform.platforms["amazon2023"] = self
|
|
25
25
|
|
|
26
|
-
#
|
|
27
|
-
#
|
|
26
|
+
# The account EC2 creates on this platform's official AMIs.
|
|
27
|
+
#
|
|
28
|
+
# Used as the SSH username when the transport does not specify one.
|
|
29
|
+
#
|
|
30
|
+
# @return [String] the default SSH username
|
|
28
31
|
def username
|
|
29
32
|
"ec2-user"
|
|
30
33
|
end
|
|
31
34
|
|
|
35
|
+
# EC2 image filters that select Amazon Linux 2023 AMIs published by AWS.
|
|
36
|
+
#
|
|
37
|
+
# A filter is added for {StandardPlatform#architecture} only when one was
|
|
38
|
+
# requested, so that an unspecified architecture matches any of them.
|
|
39
|
+
#
|
|
40
|
+
# @return [Hash{String => String, Array<String>}] filter name to the value
|
|
41
|
+
# or values it must match
|
|
42
|
+
# @see StandardPlatform#find_image
|
|
32
43
|
def image_search
|
|
33
44
|
search = {
|
|
34
45
|
"owner-id" => "137112412989",
|
|
@@ -38,10 +49,22 @@ module Kitchen
|
|
|
38
49
|
search
|
|
39
50
|
end
|
|
40
51
|
|
|
52
|
+
# Detect this platform from an EC2 image.
|
|
53
|
+
#
|
|
54
|
+
# Matching is done on the image name, which is the only reliable signal
|
|
55
|
+
# EC2 exposes about what an AMI actually contains.
|
|
56
|
+
#
|
|
57
|
+
# @param driver [Kitchen::Driver::Ec2] the driver requesting detection
|
|
58
|
+
# @param image [Aws::EC2::Image] the image to inspect
|
|
59
|
+
# @return [Amazon2023, nil] a platform when the image is Amazon Linux 2023, otherwise nil
|
|
41
60
|
def self.from_image(driver, image)
|
|
42
61
|
return unless /al2023-ami/i.match?(image.name)
|
|
43
62
|
|
|
44
|
-
|
|
63
|
+
# `(\.\d+)?`, not `(\.\d+[\.\d])?`: the character class matched the
|
|
64
|
+
# separator that follows the minor version, capturing it into the
|
|
65
|
+
# version string ("2018.03.") and failing outright when the minor
|
|
66
|
+
# version was followed by anything but a dot or digit.
|
|
67
|
+
image.name =~ /\b(\d+(\.\d+)?)/i
|
|
45
68
|
new(driver, "amazon2023", (Regexp.last_match || [])[1], image.architecture)
|
|
46
69
|
end
|
|
47
70
|
end
|
|
@@ -23,14 +23,31 @@ module Kitchen
|
|
|
23
23
|
class Centos < StandardPlatform
|
|
24
24
|
StandardPlatform.platforms["centos"] = self
|
|
25
25
|
|
|
26
|
+
# The AWS account CentOS publishes its images under. Releases from 8
|
|
27
|
+
# onwards are published directly rather than through the AWS
|
|
28
|
+
# Marketplace, so images are found by owner rather than by product.
|
|
29
|
+
#
|
|
30
|
+
# @return [String]
|
|
26
31
|
CENTOS_OWNER_ID = "125523088429".freeze
|
|
27
32
|
|
|
28
|
-
#
|
|
29
|
-
#
|
|
33
|
+
# The account EC2 creates on this platform's official AMIs.
|
|
34
|
+
#
|
|
35
|
+
# CentOS 8 and earlier ship a "centos" account; Stream 9 moved to the
|
|
36
|
+
# "ec2-user" convention used by the other EL-family distributions.
|
|
37
|
+
#
|
|
38
|
+
# @return [String] the default SSH username
|
|
30
39
|
def username
|
|
31
40
|
version && version.to_f < 9.0 ? "centos" : "ec2-user"
|
|
32
41
|
end
|
|
33
42
|
|
|
43
|
+
# EC2 image filters that select CentOS Linux and CentOS Stream images.
|
|
44
|
+
#
|
|
45
|
+
# A filter is added for {StandardPlatform#architecture} only when one was
|
|
46
|
+
# requested, so that an unspecified architecture matches any of them.
|
|
47
|
+
#
|
|
48
|
+
# @return [Hash{String => String, Array<String>}] filter name to the value
|
|
49
|
+
# or values it must match
|
|
50
|
+
# @see StandardPlatform#find_image
|
|
34
51
|
def image_search
|
|
35
52
|
# Version 8+ are published directly, not to the AWS marketplace. Use OWNER ID.
|
|
36
53
|
search = {
|
|
@@ -42,6 +59,14 @@ module Kitchen
|
|
|
42
59
|
search
|
|
43
60
|
end
|
|
44
61
|
|
|
62
|
+
# Sort images newest release first.
|
|
63
|
+
#
|
|
64
|
+
# CentOS mixes bare majors ("CentOS Stream 9") with dotted releases
|
|
65
|
+
# ("CentOS 7.9"). A bare major is scored as ".999" so that Stream 9
|
|
66
|
+
# ranks above 9.0 while still ranking below 10.
|
|
67
|
+
#
|
|
68
|
+
# @param images [Array<Aws::EC2::Image>] the images to sort
|
|
69
|
+
# @return [Array<Aws::EC2::Image>] the images, newest release first
|
|
45
70
|
def sort_by_version(images)
|
|
46
71
|
# 7.1 -> [ img1, img2, img3 ]
|
|
47
72
|
# 6 -> [ img4, img5 ]
|
|
@@ -51,6 +76,14 @@ module Kitchen
|
|
|
51
76
|
.reverse.flat_map { |_k, v| v }
|
|
52
77
|
end
|
|
53
78
|
|
|
79
|
+
# Detect this platform from an EC2 image.
|
|
80
|
+
#
|
|
81
|
+
# Matching is done on the image name, which is the only reliable signal
|
|
82
|
+
# EC2 exposes about what an AMI actually contains.
|
|
83
|
+
#
|
|
84
|
+
# @param driver [Kitchen::Driver::Ec2] the driver requesting detection
|
|
85
|
+
# @param image [Aws::EC2::Image] the image to inspect
|
|
86
|
+
# @return [Centos, nil] a platform when the image is CentOS, otherwise nil
|
|
54
87
|
def self.from_image(driver, image)
|
|
55
88
|
return unless /centos/i.match?(image.name)
|
|
56
89
|
|