kitchen-ec2 3.16.0 → 3.17.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 +4 -12
- data/lib/kitchen/driver/aws/dedicated_hosts.rb +4 -4
- data/lib/kitchen/driver/aws/instance_generator.rb +5 -13
- data/lib/kitchen/driver/aws/standard_platform/alma.rb +52 -0
- data/lib/kitchen/driver/aws/standard_platform/amazon.rb +4 -4
- data/lib/kitchen/driver/aws/standard_platform/amazon2.rb +4 -4
- data/lib/kitchen/driver/aws/standard_platform/amazon2023.rb +4 -4
- data/lib/kitchen/driver/aws/standard_platform/centos.rb +4 -4
- data/lib/kitchen/driver/aws/standard_platform/debian.rb +9 -9
- data/lib/kitchen/driver/aws/standard_platform/fedora.rb +4 -4
- data/lib/kitchen/driver/aws/standard_platform/freebsd.rb +4 -4
- data/lib/kitchen/driver/aws/standard_platform/macos.rb +4 -4
- data/lib/kitchen/driver/aws/standard_platform/rhel.rb +5 -5
- data/lib/kitchen/driver/aws/standard_platform/rocky.rb +51 -0
- data/lib/kitchen/driver/aws/standard_platform/ubuntu.rb +4 -4
- data/lib/kitchen/driver/aws/standard_platform/windows.rb +33 -34
- data/lib/kitchen/driver/aws/standard_platform.rb +25 -20
- data/lib/kitchen/driver/ec2.rb +61 -38
- data/lib/kitchen/driver/ec2_version.rb +1 -3
- metadata +27 -25
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: abdd51753a33ae7cf21aeb7f3073cd949d0c0c998eb065955b2bb8982441760a
|
4
|
+
data.tar.gz: f8a5ffd49f6213cc5822857f2af830be06fd42fe1c9a29cb60328b0fd4835e45
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b68043de14aab7e71d0b4c4570492e81b0e5b6af6e04ed0ed55df1db476f2f791de20030e0b630919a811c0605f8388719820ed3b7adf87d982b3a53b2b3d230
|
7
|
+
data.tar.gz: 74c9d0cea39fccd36f79ea1490f24946eac7ecd2670c0fe2434e1a43110727015e18472839a56b28f351e342d69eb038166edc45ecc00b4e15bfa9f393696461
|
@@ -22,16 +22,12 @@ require "aws-sdk-core/shared_credentials"
|
|
22
22
|
require "aws-sdk-core/instance_profile_credentials"
|
23
23
|
|
24
24
|
module Kitchen
|
25
|
-
|
26
25
|
module Driver
|
27
|
-
|
28
26
|
class Aws
|
29
|
-
|
30
27
|
# A class for creating and managing the EC2 client connection
|
31
28
|
#
|
32
29
|
# @author Tyler Ball <tball@chef.io>
|
33
30
|
class Client
|
34
|
-
|
35
31
|
def initialize(
|
36
32
|
region,
|
37
33
|
profile_name = "default",
|
@@ -40,12 +36,12 @@ module Kitchen
|
|
40
36
|
ssl_verify_peer = true
|
41
37
|
)
|
42
38
|
::Aws.config.update(
|
43
|
-
region
|
39
|
+
region:,
|
44
40
|
profile: profile_name,
|
45
|
-
http_proxy
|
46
|
-
ssl_verify_peer:
|
41
|
+
http_proxy:,
|
42
|
+
ssl_verify_peer:
|
47
43
|
)
|
48
|
-
::Aws.config.update(retry_limit:
|
44
|
+
::Aws.config.update(retry_limit:) unless retry_limit.nil?
|
49
45
|
end
|
50
46
|
|
51
47
|
# create a new AWS EC2 instance
|
@@ -89,11 +85,7 @@ module Kitchen
|
|
89
85
|
def resource
|
90
86
|
@resource ||= ::Aws::EC2::Resource.new
|
91
87
|
end
|
92
|
-
|
93
88
|
end
|
94
|
-
|
95
89
|
end
|
96
|
-
|
97
90
|
end
|
98
|
-
|
99
91
|
end
|
@@ -98,10 +98,10 @@ module Kitchen
|
|
98
98
|
info("Deallocating dedicated host #{host_id}")
|
99
99
|
|
100
100
|
response = ec2.client.release_hosts({ host_ids: [host_id] })
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
101
|
+
return if response.unsuccessful.empty?
|
102
|
+
|
103
|
+
warn "ERROR: Could not release dedicated host #{host_id}. Host may remain allocated and incur cost"
|
104
|
+
exit!
|
105
105
|
end
|
106
106
|
|
107
107
|
# return instance family from type
|
@@ -20,16 +20,12 @@ require "base64" unless defined?(Base64)
|
|
20
20
|
require "aws-sdk-ec2"
|
21
21
|
|
22
22
|
module Kitchen
|
23
|
-
|
24
23
|
module Driver
|
25
|
-
|
26
24
|
class Aws
|
27
|
-
|
28
25
|
# A class for encapsulating the instance payload logic
|
29
26
|
#
|
30
27
|
# @author Tyler Ball <tball@chef.io>
|
31
28
|
class InstanceGenerator
|
32
|
-
|
33
29
|
attr_reader :config, :ec2, :logger
|
34
30
|
|
35
31
|
def initialize(config, ec2, logger)
|
@@ -42,7 +38,7 @@ module Kitchen
|
|
42
38
|
# can be passed in null, others need to be ommitted if they are null
|
43
39
|
# Some fields can be passed in null, others need to be ommitted if they are null
|
44
40
|
# @return [Hash]
|
45
|
-
def ec2_instance_data
|
41
|
+
def ec2_instance_data
|
46
42
|
# Support for looking up security group id and subnet id using tags.
|
47
43
|
vpc_id = nil
|
48
44
|
client = ::Aws::EC2::Client.new(region: config[:region])
|
@@ -129,8 +125,8 @@ module Kitchen
|
|
129
125
|
# and Integers need to be represented as Strings
|
130
126
|
{ key: k, value: v.to_s }
|
131
127
|
end
|
132
|
-
instance_tag_spec = { resource_type: "instance", tags:
|
133
|
-
volume_tag_spec = { resource_type: "volume", tags:
|
128
|
+
instance_tag_spec = { resource_type: "instance", tags: }
|
129
|
+
volume_tag_spec = { resource_type: "volume", tags: }
|
134
130
|
i[:tag_specifications] = [instance_tag_spec, volume_tag_spec]
|
135
131
|
end
|
136
132
|
|
@@ -146,7 +142,7 @@ module Kitchen
|
|
146
142
|
if i.key?(:placement)
|
147
143
|
i[:placement][:tenancy] = tenancy
|
148
144
|
else
|
149
|
-
i[:placement] = { tenancy:
|
145
|
+
i[:placement] = { tenancy: }
|
150
146
|
end
|
151
147
|
end
|
152
148
|
unless config[:block_device_mappings].nil? || config[:block_device_mappings].empty?
|
@@ -190,7 +186,7 @@ module Kitchen
|
|
190
186
|
if i.key?(:placement)
|
191
187
|
i[:placement][:tenancy] = tenancy
|
192
188
|
else
|
193
|
-
i[:placement] = { tenancy:
|
189
|
+
i[:placement] = { tenancy: }
|
194
190
|
end
|
195
191
|
end
|
196
192
|
unless config[:instance_initiated_shutdown_behavior].nil? ||
|
@@ -212,11 +208,7 @@ module Kitchen
|
|
212
208
|
|
213
209
|
@user_data = Base64.encode64(raw_user_data)
|
214
210
|
end
|
215
|
-
|
216
211
|
end
|
217
|
-
|
218
212
|
end
|
219
|
-
|
220
213
|
end
|
221
|
-
|
222
214
|
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
#
|
2
|
+
# Copyright:: 2023, Jared Kauppila
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
|
16
|
+
require_relative "../standard_platform"
|
17
|
+
|
18
|
+
module Kitchen
|
19
|
+
module Driver
|
20
|
+
class Aws
|
21
|
+
class StandardPlatform
|
22
|
+
# https://wiki.almalinux.org/cloud/AWS.html
|
23
|
+
class Alma < StandardPlatform
|
24
|
+
StandardPlatform.platforms["alma"] = self
|
25
|
+
StandardPlatform.platforms["almalinux"] = self
|
26
|
+
|
27
|
+
# default username for this platform's ami
|
28
|
+
# @return [String]
|
29
|
+
def username
|
30
|
+
"ec2-user"
|
31
|
+
end
|
32
|
+
|
33
|
+
def image_search
|
34
|
+
search = {
|
35
|
+
"owner-id" => "764336703387",
|
36
|
+
"name" => version ? "AlmaLinux OS #{version}*" : "AlmaLinux OS *",
|
37
|
+
}
|
38
|
+
search["architecture"] = architecture if architecture
|
39
|
+
search
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.from_image(driver, image)
|
43
|
+
return unless /AlmaLinux OS/i.match?(image.name)
|
44
|
+
|
45
|
+
image.name =~ /\b(\d+(\.\d+)?)\b/i
|
46
|
+
new(driver, "alma", (Regexp.last_match || [])[1], image.architecture)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -39,10 +39,10 @@ module Kitchen
|
|
39
39
|
end
|
40
40
|
|
41
41
|
def self.from_image(driver, image)
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
42
|
+
return unless /amzn-ami/i.match?(image.name)
|
43
|
+
|
44
|
+
image.name =~ /\b(\d+(\.\d+[\.\d])?)/i
|
45
|
+
new(driver, "amazon", (Regexp.last_match || [])[1], image.architecture)
|
46
46
|
end
|
47
47
|
end
|
48
48
|
end
|
@@ -39,10 +39,10 @@ module Kitchen
|
|
39
39
|
end
|
40
40
|
|
41
41
|
def self.from_image(driver, image)
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
42
|
+
return unless /amzn2-ami/i.match?(image.name)
|
43
|
+
|
44
|
+
image.name =~ /\b(\d+(\.\d+[\.\d])?)/i
|
45
|
+
new(driver, "amazon2", (Regexp.last_match || [])[1], image.architecture)
|
46
46
|
end
|
47
47
|
end
|
48
48
|
end
|
@@ -39,10 +39,10 @@ module Kitchen
|
|
39
39
|
end
|
40
40
|
|
41
41
|
def self.from_image(driver, image)
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
42
|
+
return unless /al2023-ami/i.match?(image.name)
|
43
|
+
|
44
|
+
image.name =~ /\b(\d+(\.\d+[\.\d])?)/i
|
45
|
+
new(driver, "amazon2023", (Regexp.last_match || [])[1], image.architecture)
|
46
46
|
end
|
47
47
|
end
|
48
48
|
end
|
@@ -52,10 +52,10 @@ module Kitchen
|
|
52
52
|
end
|
53
53
|
|
54
54
|
def self.from_image(driver, image)
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
55
|
+
return unless /centos/i.match?(image.name)
|
56
|
+
|
57
|
+
image.name =~ /\b(\d+(\.\d+)?)\b/i
|
58
|
+
new(driver, "centos", (Regexp.last_match || [])[1], image.architecture)
|
59
59
|
end
|
60
60
|
end
|
61
61
|
end
|
@@ -73,16 +73,16 @@ module Kitchen
|
|
73
73
|
end
|
74
74
|
|
75
75
|
def self.from_image(driver, image)
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
end
|
84
|
-
new(driver, "debian", version, image.architecture)
|
76
|
+
return unless /debian/i.match?(image.name)
|
77
|
+
|
78
|
+
image.name =~ /\b(\d+|#{DEBIAN_CODENAMES.values.join("|")})\b/i
|
79
|
+
version = (Regexp.last_match || [])[1]
|
80
|
+
if version&.to_i&.zero?
|
81
|
+
version = DEBIAN_CODENAMES.find do |_v, codename|
|
82
|
+
codename == version.downcase
|
83
|
+
end.first
|
85
84
|
end
|
85
|
+
new(driver, "debian", version, image.architecture)
|
86
86
|
end
|
87
87
|
end
|
88
88
|
end
|
@@ -39,10 +39,10 @@ module Kitchen
|
|
39
39
|
end
|
40
40
|
|
41
41
|
def self.from_image(driver, image)
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
42
|
+
return unless /fedora/i.match?(image.name)
|
43
|
+
|
44
|
+
image.name =~ /\b(\d+(\.\d+)?)\b/i
|
45
|
+
new(driver, "fedora", (Regexp.last_match || [])[1], image.architecture)
|
46
46
|
end
|
47
47
|
end
|
48
48
|
end
|
@@ -41,10 +41,10 @@ module Kitchen
|
|
41
41
|
end
|
42
42
|
|
43
43
|
def self.from_image(driver, image)
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
44
|
+
return unless /freebsd/i.match?(image.name)
|
45
|
+
|
46
|
+
image.name =~ /\b(\d+(\.\d+)?)\b/i
|
47
|
+
new(driver, "freebsd", (Regexp.last_match || [])[1], image.architecture)
|
48
48
|
end
|
49
49
|
end
|
50
50
|
end
|
@@ -39,10 +39,10 @@ module Kitchen
|
|
39
39
|
end
|
40
40
|
|
41
41
|
def self.from_image(driver, image)
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
42
|
+
return unless /amzn-ec2-macos/i.match?(image.name)
|
43
|
+
|
44
|
+
image.name =~ /\b(\d+(\.\d+[\.\d])?)/i
|
45
|
+
new(driver, "macos", (Regexp.last_match || [])[1], image.architecture)
|
46
46
|
end
|
47
47
|
end
|
48
48
|
end
|
@@ -32,7 +32,7 @@ module Kitchen
|
|
32
32
|
# default username for this platform's ami
|
33
33
|
# @return [String]
|
34
34
|
def username
|
35
|
-
|
35
|
+
version && version.to_f < 6.4 ? "root" : "ec2-user"
|
36
36
|
end
|
37
37
|
|
38
38
|
def image_search
|
@@ -45,10 +45,10 @@ module Kitchen
|
|
45
45
|
end
|
46
46
|
|
47
47
|
def self.from_image(driver, image)
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
48
|
+
return unless /rhel/i.match?(image.name)
|
49
|
+
|
50
|
+
image.name =~ /\b(\d+(\.\d+)?)/i
|
51
|
+
new(driver, "rhel", (Regexp.last_match || [])[1], image.architecture)
|
52
52
|
end
|
53
53
|
|
54
54
|
def sort_by_version(images)
|
@@ -0,0 +1,51 @@
|
|
1
|
+
#
|
2
|
+
# Copyright:: 2023, Jared Kauppila
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
|
16
|
+
require_relative "../standard_platform"
|
17
|
+
|
18
|
+
module Kitchen
|
19
|
+
module Driver
|
20
|
+
class Aws
|
21
|
+
class StandardPlatform
|
22
|
+
class Rocky < StandardPlatform
|
23
|
+
StandardPlatform.platforms["rocky"] = self
|
24
|
+
StandardPlatform.platforms["rockylinux"] = self
|
25
|
+
|
26
|
+
# default username for this platform's ami
|
27
|
+
# @return [String]
|
28
|
+
def username
|
29
|
+
"rocky"
|
30
|
+
end
|
31
|
+
|
32
|
+
def image_search
|
33
|
+
search = {
|
34
|
+
"owner-id" => "792107900819",
|
35
|
+
"name" => version ? "Rocky-#{version}-*" : "Rocky-*",
|
36
|
+
}
|
37
|
+
search["architecture"] = architecture if architecture
|
38
|
+
search
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.from_image(driver, image)
|
42
|
+
return unless /Rocky-/i.match?(image.name)
|
43
|
+
|
44
|
+
image.name =~ /\b(\d+(\.\d+[\.\d])?)/i
|
45
|
+
new(driver, "rocky", (Regexp.last_match || [])[1], image.architecture)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -39,10 +39,10 @@ module Kitchen
|
|
39
39
|
end
|
40
40
|
|
41
41
|
def self.from_image(driver, image)
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
42
|
+
return unless /ubuntu/i.match?(image.name)
|
43
|
+
|
44
|
+
image.name =~ /\b(\d+(\.\d+)?)\b/i
|
45
|
+
new(driver, "ubuntu", (Regexp.last_match || [])[1], image.architecture)
|
46
46
|
end
|
47
47
|
end
|
48
48
|
end
|
@@ -70,21 +70,20 @@ module Kitchen
|
|
70
70
|
end
|
71
71
|
|
72
72
|
def self.from_image(driver, image)
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
end
|
85
|
-
|
86
|
-
new(driver, "windows", version, image.architecture)
|
73
|
+
return unless /Windows/i.match?(image.name)
|
74
|
+
|
75
|
+
# 2008 R2 SP2
|
76
|
+
if image.name =~ /(\b\d+)\W*(r\d+)?/i
|
77
|
+
major = (Regexp.last_match || [])[1]
|
78
|
+
revision = (Regexp.last_match || [])[2]
|
79
|
+
service_pack = (Regexp.last_match || [])[1] if image.name =~ /(sp\d+|rtm)/i
|
80
|
+
revision = revision.downcase if revision
|
81
|
+
service_pack ||= "rtm"
|
82
|
+
service_pack = service_pack.downcase
|
83
|
+
version = "#{major}#{revision}#{service_pack}"
|
87
84
|
end
|
85
|
+
|
86
|
+
new(driver, "windows", version, image.architecture)
|
88
87
|
end
|
89
88
|
|
90
89
|
protected
|
@@ -132,30 +131,30 @@ module Kitchen
|
|
132
131
|
|
133
132
|
private
|
134
133
|
|
135
|
-
def windows_name_filter
|
134
|
+
def windows_name_filter
|
136
135
|
major, revision, service_pack = windows_version_parts
|
137
|
-
if
|
136
|
+
if [2022, 2019, 2016].include?(major)
|
138
137
|
"Windows_Server-#{major}-English-Full-Base-*"
|
139
|
-
elsif
|
138
|
+
elsif [1709, 1803].include?(major)
|
140
139
|
"Windows_Server-#{major}-English-Core-ContainersLatest-*"
|
141
140
|
else
|
142
|
-
case revision
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
case service_pack
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
141
|
+
revision_strings = case revision
|
142
|
+
when nil
|
143
|
+
["", "R*_"]
|
144
|
+
when 0
|
145
|
+
[""]
|
146
|
+
else
|
147
|
+
["R#{revision}_"]
|
148
|
+
end
|
149
|
+
|
150
|
+
revision_strings = case service_pack
|
151
|
+
when nil
|
152
|
+
revision_strings.flat_map { |r| ["#{r}RTM", "#{r}SP*"] }
|
153
|
+
when 0
|
154
|
+
revision_strings.map { |r| "#{r}RTM" }
|
155
|
+
else
|
156
|
+
revision_strings.map { |r| "#{r}SP#{service_pack}" }
|
157
|
+
end
|
159
158
|
|
160
159
|
name_filter = revision_strings.map do |r|
|
161
160
|
"Windows_Server-#{major || "*"}-#{r}-English-*-Base-*"
|
@@ -91,6 +91,11 @@ module Kitchen
|
|
91
91
|
#
|
92
92
|
SUPPORTED_ARCHITECTURES = %w{x86_64 i386 arm64}.freeze
|
93
93
|
|
94
|
+
#
|
95
|
+
# The list of supported ebs volume types
|
96
|
+
#
|
97
|
+
EBS_VOLUME_TYPES = %w{gp3 gp2}.freeze
|
98
|
+
|
94
99
|
#
|
95
100
|
# Find the best matching image for the given image search.
|
96
101
|
#
|
@@ -103,12 +108,12 @@ module Kitchen
|
|
103
108
|
end
|
104
109
|
|
105
110
|
# We prefer most recent first
|
106
|
-
images = driver.ec2.resource.images(filters:
|
111
|
+
images = driver.ec2.resource.images(filters:)
|
107
112
|
images = sort_images(images)
|
108
113
|
show_returned_images(images)
|
109
114
|
|
110
115
|
# Grab the best match
|
111
|
-
images.first
|
116
|
+
images.first&.id
|
112
117
|
end
|
113
118
|
|
114
119
|
#
|
@@ -136,9 +141,9 @@ module Kitchen
|
|
136
141
|
#
|
137
142
|
def self.from_platform_string(driver, platform_string)
|
138
143
|
platform, version, architecture = parse_platform_string(platform_string)
|
139
|
-
|
140
|
-
|
141
|
-
|
144
|
+
return unless platform && platforms[platform]
|
145
|
+
|
146
|
+
platforms[platform].new(driver, platform, version, architecture)
|
142
147
|
end
|
143
148
|
|
144
149
|
#
|
@@ -157,6 +162,20 @@ module Kitchen
|
|
157
162
|
nil
|
158
163
|
end
|
159
164
|
|
165
|
+
def self.parse_platform_string(platform_string)
|
166
|
+
platform, version = platform_string.split("-", 2)
|
167
|
+
|
168
|
+
# If the right side is a valid architecture, use it as such
|
169
|
+
# i.e. debian-i386 or windows-server-2012r2-i386
|
170
|
+
if version && SUPPORTED_ARCHITECTURES.include?(version.split("-")[-1])
|
171
|
+
# server-2012r2-i386 -> server-2012r2, -, i386
|
172
|
+
version, _dash, architecture = version.rpartition("-")
|
173
|
+
version = nil if version == ""
|
174
|
+
end
|
175
|
+
|
176
|
+
[platform, version, architecture]
|
177
|
+
end
|
178
|
+
|
160
179
|
protected
|
161
180
|
|
162
181
|
#
|
@@ -192,20 +211,6 @@ module Kitchen
|
|
192
211
|
|
193
212
|
private
|
194
213
|
|
195
|
-
def self.parse_platform_string(platform_string)
|
196
|
-
platform, version = platform_string.split("-", 2)
|
197
|
-
|
198
|
-
# If the right side is a valid architecture, use it as such
|
199
|
-
# i.e. debian-i386 or windows-server-2012r2-i386
|
200
|
-
if version && SUPPORTED_ARCHITECTURES.include?(version.split("-")[-1])
|
201
|
-
# server-2012r2-i386 -> server-2012r2, -, i386
|
202
|
-
version, _dash, architecture = version.rpartition("-")
|
203
|
-
version = nil if version == ""
|
204
|
-
end
|
205
|
-
|
206
|
-
[platform, version, architecture]
|
207
|
-
end
|
208
|
-
|
209
214
|
def sort_images(images)
|
210
215
|
# P6: We prefer more recent images over older ones
|
211
216
|
images = images.sort_by(&:creation_date).reverse
|
@@ -214,7 +219,7 @@ module Kitchen
|
|
214
219
|
# P4: We prefer (SSD) (if available)
|
215
220
|
images = prefer(images) do |image|
|
216
221
|
image.block_device_mappings.any? do |b|
|
217
|
-
b.device_name == image.root_device_name && b.ebs &&
|
222
|
+
b.device_name == image.root_device_name && b.ebs && EBS_VOLUME_TYPES.any?(b.ebs.volume_type)
|
218
223
|
end
|
219
224
|
end
|
220
225
|
# P3: We prefer ebs over instance_store (if available)
|
data/lib/kitchen/driver/ec2.rb
CHANGED
@@ -24,12 +24,14 @@ require_relative "aws/client"
|
|
24
24
|
require_relative "aws/dedicated_hosts"
|
25
25
|
require_relative "aws/instance_generator"
|
26
26
|
require_relative "aws/standard_platform"
|
27
|
+
require_relative "aws/standard_platform/alma"
|
27
28
|
require_relative "aws/standard_platform/amazon"
|
28
29
|
require_relative "aws/standard_platform/amazon2"
|
29
30
|
require_relative "aws/standard_platform/amazon2023"
|
30
31
|
require_relative "aws/standard_platform/centos"
|
31
32
|
require_relative "aws/standard_platform/debian"
|
32
33
|
require_relative "aws/standard_platform/rhel"
|
34
|
+
require_relative "aws/standard_platform/rocky"
|
33
35
|
require_relative "aws/standard_platform/fedora"
|
34
36
|
require_relative "aws/standard_platform/freebsd"
|
35
37
|
require_relative "aws/standard_platform/macos"
|
@@ -43,20 +45,17 @@ require "etc" unless defined?(Etc)
|
|
43
45
|
require "socket" unless defined?(Socket)
|
44
46
|
|
45
47
|
module Kitchen
|
46
|
-
|
47
48
|
module Driver
|
48
|
-
|
49
49
|
# Amazon EC2 driver for Test Kitchen.
|
50
50
|
#
|
51
51
|
# @author Fletcher Nichol <fnichol@nichol.ca>
|
52
52
|
class Ec2 < Kitchen::Driver::Base
|
53
|
-
|
54
53
|
kitchen_driver_api_version 2
|
55
54
|
|
56
55
|
plugin_version Kitchen::Driver::EC2_VERSION
|
57
56
|
|
58
57
|
default_config :region, ENV["AWS_REGION"] || "us-east-1"
|
59
|
-
default_config :shared_credentials_profile, ENV
|
58
|
+
default_config :shared_credentials_profile, ENV.fetch("AWS_PROFILE", nil)
|
60
59
|
default_config :availability_zone, nil
|
61
60
|
default_config :instance_type, &:default_instance_type
|
62
61
|
default_config :ebs_optimized, false
|
@@ -80,14 +79,14 @@ module Kitchen
|
|
80
79
|
default_config :aws_access_key_id, nil
|
81
80
|
default_config :aws_secret_access_key, nil
|
82
81
|
default_config :aws_session_token, nil
|
83
|
-
default_config :aws_ssh_key_id, ENV
|
82
|
+
default_config :aws_ssh_key_id, ENV.fetch("AWS_SSH_KEY_ID", nil)
|
84
83
|
default_config :aws_ssh_key_type, "rsa"
|
85
84
|
default_config :image_id, &:default_ami
|
86
85
|
default_config :image_search, nil
|
87
86
|
default_config :username, nil
|
88
87
|
default_config :associate_public_ip, nil
|
89
88
|
default_config :interface, nil
|
90
|
-
default_config :http_proxy, ENV["HTTPS_PROXY"] || ENV
|
89
|
+
default_config :http_proxy, ENV["HTTPS_PROXY"] || ENV.fetch("HTTP_PROXY", nil)
|
91
90
|
default_config :retry_limit, 3
|
92
91
|
default_config :tenancy, "default"
|
93
92
|
default_config :instance_initiated_shutdown_behavior, nil
|
@@ -192,10 +191,10 @@ module Kitchen
|
|
192
191
|
end
|
193
192
|
|
194
193
|
# empty keys cause failures when tagging and they make no sense
|
195
|
-
validations[:tags] = lambda do |
|
194
|
+
validations[:tags] = lambda do |_attr, val, _driver|
|
196
195
|
# if someone puts the tags each on their own line it's an array not a hash
|
197
196
|
# @todo we should probably just do the right thing and support this format
|
198
|
-
if val.
|
197
|
+
if val.instance_of?(Array)
|
199
198
|
warn "AWS instance tags must be specified as a single hash, not a tag " \
|
200
199
|
"on each line. Example: {:foo => 'bar', :bar => 'foo'}"
|
201
200
|
exit!
|
@@ -245,13 +244,13 @@ module Kitchen
|
|
245
244
|
info("Auto placement on one dedicated host out of: #{hosts_with_capacity.map(&:host_id).join(", ")}")
|
246
245
|
end
|
247
246
|
|
248
|
-
if config[:spot_price]
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
247
|
+
server = if config[:spot_price]
|
248
|
+
# Spot instance when a price is set
|
249
|
+
with_request_limit_backoff(state) { submit_spots }
|
250
|
+
else
|
251
|
+
# On-demand instance
|
252
|
+
with_request_limit_backoff(state) { submit_server }
|
253
|
+
end
|
255
254
|
info("Instance <#{server.id}> requested.")
|
256
255
|
with_request_limit_backoff(state) do
|
257
256
|
logging_proc = ->(attempts) { info("Polling AWS for existence, attempt #{attempts}...") }
|
@@ -267,7 +266,7 @@ module Kitchen
|
|
267
266
|
tries: 10,
|
268
267
|
sleep: lambda { |n| [2**n, 30].min },
|
269
268
|
on: ::Aws::EC2::Errors::InvalidInstanceIDNotFound
|
270
|
-
) do |
|
269
|
+
) do |_r, _|
|
271
270
|
wait_until_ready(server, state)
|
272
271
|
end
|
273
272
|
|
@@ -318,10 +317,10 @@ module Kitchen
|
|
318
317
|
delete_key(state)
|
319
318
|
|
320
319
|
# Clean up dedicated hosts matching instance_type and unused (if allowed)
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
320
|
+
return unless config[:tenancy] == "host" && allow_deallocate_host?
|
321
|
+
|
322
|
+
empty_hosts = hosts_with_capacity.select { |host| host_unused?(host) }
|
323
|
+
empty_hosts.each { |host| deallocate_host(host.host_id) }
|
325
324
|
end
|
326
325
|
|
327
326
|
def image
|
@@ -425,7 +424,7 @@ module Kitchen
|
|
425
424
|
def expand_config(conf, key)
|
426
425
|
configs = []
|
427
426
|
|
428
|
-
if conf[key]
|
427
|
+
if conf[key].is_a?(Array)
|
429
428
|
values = conf[key]
|
430
429
|
values.each do |value|
|
431
430
|
new_config = conf.clone
|
@@ -497,11 +496,11 @@ module Kitchen
|
|
497
496
|
instance_data = instance_generator.ec2_instance_data
|
498
497
|
|
499
498
|
config_spot_price = config[:spot_price].to_s
|
500
|
-
if %w{ondemand on-demand}.include?(config_spot_price)
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
499
|
+
spot_price = if %w{ondemand on-demand}.include?(config_spot_price)
|
500
|
+
""
|
501
|
+
else
|
502
|
+
config_spot_price
|
503
|
+
end
|
505
504
|
spot_options = {
|
506
505
|
# Must use one-time in order to use instance_interruption_behavior=terminate
|
507
506
|
# spot_instance_type: "one-time", # default
|
@@ -517,7 +516,7 @@ module Kitchen
|
|
517
516
|
|
518
517
|
instance_data[:instance_market_options] = {
|
519
518
|
market_type: "spot",
|
520
|
-
spot_options
|
519
|
+
spot_options:,
|
521
520
|
}
|
522
521
|
|
523
522
|
# The preferred way to create a spot instance is via request_spot_instances()
|
@@ -549,7 +548,7 @@ module Kitchen
|
|
549
548
|
aws_instance.state.name == "running" &&
|
550
549
|
hostname != "0.0.0.0"
|
551
550
|
|
552
|
-
if ready && (
|
551
|
+
if ready && (hostname.nil? || hostname == "")
|
553
552
|
debug("Unable to detect hostname using interface_type #{config[:interface]}. Fallback to ordered mapping")
|
554
553
|
state[:hostname] = hostname(aws_instance, nil)
|
555
554
|
end
|
@@ -565,7 +564,7 @@ module Kitchen
|
|
565
564
|
output = Base64.decode64(output)
|
566
565
|
debug "Console output: --- \n#{output}"
|
567
566
|
end
|
568
|
-
ready = !!(output
|
567
|
+
ready = !!(output.include?("Windows is Ready to use"))
|
569
568
|
end
|
570
569
|
end
|
571
570
|
ready
|
@@ -598,7 +597,7 @@ module Kitchen
|
|
598
597
|
end
|
599
598
|
|
600
599
|
def fetch_windows_admin_password(server, state)
|
601
|
-
wait_with_destroy(server, state, "to fetch windows admin password") do |
|
600
|
+
wait_with_destroy(server, state, "to fetch windows admin password") do |_aws_instance|
|
602
601
|
enc = server.client.get_password_data(
|
603
602
|
instance_id: state[:server_id]
|
604
603
|
).password_data
|
@@ -653,7 +652,7 @@ module Kitchen
|
|
653
652
|
server.send(interface_type)
|
654
653
|
else
|
655
654
|
potential_hostname = nil
|
656
|
-
INTERFACE_TYPES.
|
655
|
+
INTERFACE_TYPES.each_value do |type|
|
657
656
|
potential_hostname ||= server.send(type)
|
658
657
|
# AWS returns an empty string if the dns name isn't populated yet
|
659
658
|
potential_hostname = nil if potential_hostname == ""
|
@@ -715,7 +714,7 @@ module Kitchen
|
|
715
714
|
|
716
715
|
# Preparing custom static admin user if we defined something other than Administrator
|
717
716
|
custom_admin_script = ""
|
718
|
-
if
|
717
|
+
if instance.transport[:username] !~ /administrator/i && instance.transport[:password]
|
719
718
|
custom_admin_script = Kitchen::Util.outdent!(<<-EOH)
|
720
719
|
"Disabling Complex Passwords" >> $logfile
|
721
720
|
$seccfg = [IO.Path]::GetTempFileName()
|
@@ -757,7 +756,7 @@ module Kitchen
|
|
757
756
|
def image_info(image)
|
758
757
|
root_device = image.block_device_mappings
|
759
758
|
.find { |b| b.device_name == image.root_device_name }
|
760
|
-
volume_type = " #{root_device.ebs.volume_type}" if root_device
|
759
|
+
volume_type = " #{root_device.ebs.volume_type}" if root_device&.ebs
|
761
760
|
|
762
761
|
" Architecture: #{image.architecture}," \
|
763
762
|
" Virtualization: #{image.virtualization_type}," \
|
@@ -811,6 +810,17 @@ module Kitchen
|
|
811
810
|
params = {
|
812
811
|
group_name: "kitchen-#{Array.new(8) { rand(36).to_s(36) }.join}",
|
813
812
|
description: "Test Kitchen for #{instance.name} by #{Etc.getlogin || "nologin"} on #{Socket.gethostname}",
|
813
|
+
tag_specifications: [
|
814
|
+
{
|
815
|
+
resource_type: "security-group",
|
816
|
+
tags: [
|
817
|
+
{
|
818
|
+
key: "created-by",
|
819
|
+
value: "test-kitchen",
|
820
|
+
},
|
821
|
+
],
|
822
|
+
},
|
823
|
+
],
|
814
824
|
}
|
815
825
|
params[:vpc_id] = vpc_id if vpc_id
|
816
826
|
resp = ec2.client.create_security_group(params)
|
@@ -827,7 +837,7 @@ module Kitchen
|
|
827
837
|
from_port: port,
|
828
838
|
to_port: port,
|
829
839
|
ip_ranges: Array(config[:security_group_cidr_ip]).map do |cidr_ip|
|
830
|
-
{ cidr_ip:
|
840
|
+
{ cidr_ip: }
|
831
841
|
end,
|
832
842
|
}
|
833
843
|
end
|
@@ -849,14 +859,28 @@ module Kitchen
|
|
849
859
|
(Etc.getlogin || "nologin").gsub(/\W/, ""),
|
850
860
|
Socket.gethostname.gsub(/\W/, "")[0..20],
|
851
861
|
Time.now.utc.iso8601,
|
852
|
-
Array.new(8) { rand(36).to_s(36) }.join
|
862
|
+
Array.new(8) { rand(36).to_s(36) }.join,
|
853
863
|
]
|
854
864
|
# In a perfect world this would generate the key locally and use ImportKey
|
855
865
|
# instead for better security, but given the use case that is very likely
|
856
866
|
# to rapidly exhaust local entropy by creating a lot of keys. So this is
|
857
867
|
# probably fine. If you want very high security, probably don't use this
|
858
868
|
# feature anyway.
|
859
|
-
resp = ec2.client.create_key_pair(
|
869
|
+
resp = ec2.client.create_key_pair(
|
870
|
+
key_name: "kitchen-#{name_parts.join("-")}",
|
871
|
+
key_type: config[:aws_ssh_key_type],
|
872
|
+
tag_specifications: [
|
873
|
+
{
|
874
|
+
resource_type: "key-pair",
|
875
|
+
tags: [
|
876
|
+
{
|
877
|
+
key: "created-by",
|
878
|
+
value: "test-kitchen",
|
879
|
+
},
|
880
|
+
],
|
881
|
+
},
|
882
|
+
]
|
883
|
+
)
|
860
884
|
state[:auto_key_id] = resp.key_name
|
861
885
|
info("Created automatic key pair #{state[:auto_key_id]}")
|
862
886
|
# Write the key out with safe permissions
|
@@ -890,7 +914,7 @@ module Kitchen
|
|
890
914
|
puts "ENI #{config[:elastic_network_interface_id]} already attached."
|
891
915
|
end
|
892
916
|
rescue ::Aws::EC2::Errors::InvalidNetworkInterfaceIDNotFound => e
|
893
|
-
warn(
|
917
|
+
warn(e.to_s)
|
894
918
|
end
|
895
919
|
end
|
896
920
|
|
@@ -920,7 +944,6 @@ module Kitchen
|
|
920
944
|
state.delete(:auto_key_id)
|
921
945
|
File.unlink("#{config[:kitchen_root]}/.kitchen/#{instance.name}.pem")
|
922
946
|
end
|
923
|
-
|
924
947
|
end
|
925
948
|
end
|
926
949
|
end
|
metadata
CHANGED
@@ -1,35 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kitchen-ec2
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.17.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: 2023-
|
11
|
+
date: 2023-11-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
-
- !ruby/object:Gem::Dependency
|
14
|
-
name: test-kitchen
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - ">="
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: 1.4.1
|
20
|
-
- - "<"
|
21
|
-
- !ruby/object:Gem::Version
|
22
|
-
version: '4'
|
23
|
-
type: :runtime
|
24
|
-
prerelease: false
|
25
|
-
version_requirements: !ruby/object:Gem::Requirement
|
26
|
-
requirements:
|
27
|
-
- - ">="
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
version: 1.4.1
|
30
|
-
- - "<"
|
31
|
-
- !ruby/object:Gem::Version
|
32
|
-
version: '4'
|
33
13
|
- !ruby/object:Gem::Dependency
|
34
14
|
name: aws-sdk-ec2
|
35
15
|
requirement: !ruby/object:Gem::Requirement
|
@@ -64,9 +44,29 @@ dependencies:
|
|
64
44
|
- - "<"
|
65
45
|
- !ruby/object:Gem::Version
|
66
46
|
version: '4.0'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: test-kitchen
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 1.4.1
|
54
|
+
- - "<"
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '4'
|
57
|
+
type: :runtime
|
58
|
+
prerelease: false
|
59
|
+
version_requirements: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: 1.4.1
|
64
|
+
- - "<"
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '4'
|
67
67
|
description: A Test Kitchen Driver for Amazon EC2
|
68
68
|
email:
|
69
|
-
-
|
69
|
+
- help@sous-chefs.org
|
70
70
|
executables: []
|
71
71
|
extensions: []
|
72
72
|
extra_rdoc_files: []
|
@@ -76,6 +76,7 @@ files:
|
|
76
76
|
- lib/kitchen/driver/aws/dedicated_hosts.rb
|
77
77
|
- lib/kitchen/driver/aws/instance_generator.rb
|
78
78
|
- lib/kitchen/driver/aws/standard_platform.rb
|
79
|
+
- lib/kitchen/driver/aws/standard_platform/alma.rb
|
79
80
|
- lib/kitchen/driver/aws/standard_platform/amazon.rb
|
80
81
|
- lib/kitchen/driver/aws/standard_platform/amazon2.rb
|
81
82
|
- lib/kitchen/driver/aws/standard_platform/amazon2023.rb
|
@@ -85,6 +86,7 @@ files:
|
|
85
86
|
- lib/kitchen/driver/aws/standard_platform/freebsd.rb
|
86
87
|
- lib/kitchen/driver/aws/standard_platform/macos.rb
|
87
88
|
- lib/kitchen/driver/aws/standard_platform/rhel.rb
|
89
|
+
- lib/kitchen/driver/aws/standard_platform/rocky.rb
|
88
90
|
- lib/kitchen/driver/aws/standard_platform/ubuntu.rb
|
89
91
|
- lib/kitchen/driver/aws/standard_platform/windows.rb
|
90
92
|
- lib/kitchen/driver/ec2.rb
|
@@ -108,7 +110,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
108
110
|
- !ruby/object:Gem::Version
|
109
111
|
version: '0'
|
110
112
|
requirements: []
|
111
|
-
rubygems_version: 3.4.
|
113
|
+
rubygems_version: 3.4.10
|
112
114
|
signing_key:
|
113
115
|
specification_version: 4
|
114
116
|
summary: A Test Kitchen Driver for Amazon EC2
|