kitchen-ec2 3.17.0 → 3.18.0
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 +42 -13
- data/lib/kitchen/driver/aws/standard_platform/alma.rb +4 -4
- 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 +4 -4
- 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 +59 -38
- data/lib/kitchen/driver/ec2_version.rb +1 -3
- metadata +25 -25
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5a5e24ca8e2d208d63f7079597ea3d8c3773eab8d82891ec1052f226dfb0d3b2
|
4
|
+
data.tar.gz: 6bd3c4846bc622f399ee748e2e5e15d5aaf1dc2b70d8db875ac3d20897fdb58e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9016a081a3b1cd4cfc2bcf57e02df07a6f3225b610a2087ef45dd5d5da3fb8dc9db823675283cb7e6eba5c0cb90174b705244bed5222eedf3211a06cf06a7659
|
7
|
+
data.tar.gz: 3ec395554c6ff841f46be8610b2b6c7ae9b19d58af87c3b786589df73950cbbb3864b533691fd2015ec075d29697ec850b381e99fadd3f17762799d953523dc4
|
@@ -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,44 @@ 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: }
|
190
|
+
end
|
191
|
+
end
|
192
|
+
placement = config[:placement]
|
193
|
+
if placement
|
194
|
+
unless i.key?(:placement)
|
195
|
+
i[:placement] = {}
|
196
|
+
end
|
197
|
+
if placement[:affinity]
|
198
|
+
i[:placement][:affinity] = placement[:affinity]
|
199
|
+
end
|
200
|
+
if placement[:availability_zone]
|
201
|
+
i[:placement][:availability_zone] = placement[:availability_zone]
|
202
|
+
end
|
203
|
+
if placement[:group_id] && !placement[:group_name]
|
204
|
+
i[:placement][:group_id] = placement[:group_id]
|
205
|
+
end
|
206
|
+
if placement[:group_name] && !placement[:group_id]
|
207
|
+
i[:placement][:group_name] = placement[:group_name]
|
208
|
+
end
|
209
|
+
if placement[:host_id]
|
210
|
+
i[:placement][:host_id] = placement[:host_id]
|
211
|
+
end
|
212
|
+
if placement[:host_resource_group_arn]
|
213
|
+
i[:placement][:host_resource_group_arn] = placement[:host_resource_group_arn]
|
214
|
+
end
|
215
|
+
if placement[:partition_number]
|
216
|
+
i[:placement][:partition_number] = placement[:partition_number]
|
217
|
+
end
|
218
|
+
if placement[:tenancy]
|
219
|
+
i[:placement][:tenancy] = placement[:tenancy]
|
220
|
+
end
|
221
|
+
end
|
222
|
+
license_specifications = config[:licenses]
|
223
|
+
if license_specifications
|
224
|
+
i[:licenses] = []
|
225
|
+
license_specifications.each do |license_configuration_arn|
|
226
|
+
i[:licenses].append({ license_configuration_arn: license_configuration_arn[:license_configuration_arn] })
|
194
227
|
end
|
195
228
|
end
|
196
229
|
unless config[:instance_initiated_shutdown_behavior].nil? ||
|
@@ -212,11 +245,7 @@ module Kitchen
|
|
212
245
|
|
213
246
|
@user_data = Base64.encode64(raw_user_data)
|
214
247
|
end
|
215
|
-
|
216
248
|
end
|
217
|
-
|
218
249
|
end
|
219
|
-
|
220
250
|
end
|
221
|
-
|
222
251
|
end
|
@@ -40,10 +40,10 @@ module Kitchen
|
|
40
40
|
end
|
41
41
|
|
42
42
|
def self.from_image(driver, image)
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
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
47
|
end
|
48
48
|
end
|
49
49
|
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)
|
@@ -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 /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
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 /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
@@ -45,20 +45,17 @@ require "etc" unless defined?(Etc)
|
|
45
45
|
require "socket" unless defined?(Socket)
|
46
46
|
|
47
47
|
module Kitchen
|
48
|
-
|
49
48
|
module Driver
|
50
|
-
|
51
49
|
# Amazon EC2 driver for Test Kitchen.
|
52
50
|
#
|
53
51
|
# @author Fletcher Nichol <fnichol@nichol.ca>
|
54
52
|
class Ec2 < Kitchen::Driver::Base
|
55
|
-
|
56
53
|
kitchen_driver_api_version 2
|
57
54
|
|
58
55
|
plugin_version Kitchen::Driver::EC2_VERSION
|
59
56
|
|
60
57
|
default_config :region, ENV["AWS_REGION"] || "us-east-1"
|
61
|
-
default_config :shared_credentials_profile, ENV
|
58
|
+
default_config :shared_credentials_profile, ENV.fetch("AWS_PROFILE", nil)
|
62
59
|
default_config :availability_zone, nil
|
63
60
|
default_config :instance_type, &:default_instance_type
|
64
61
|
default_config :ebs_optimized, false
|
@@ -82,14 +79,14 @@ module Kitchen
|
|
82
79
|
default_config :aws_access_key_id, nil
|
83
80
|
default_config :aws_secret_access_key, nil
|
84
81
|
default_config :aws_session_token, nil
|
85
|
-
default_config :aws_ssh_key_id, ENV
|
82
|
+
default_config :aws_ssh_key_id, ENV.fetch("AWS_SSH_KEY_ID", nil)
|
86
83
|
default_config :aws_ssh_key_type, "rsa"
|
87
84
|
default_config :image_id, &:default_ami
|
88
85
|
default_config :image_search, nil
|
89
86
|
default_config :username, nil
|
90
87
|
default_config :associate_public_ip, nil
|
91
88
|
default_config :interface, nil
|
92
|
-
default_config :http_proxy, ENV["HTTPS_PROXY"] || ENV
|
89
|
+
default_config :http_proxy, ENV["HTTPS_PROXY"] || ENV.fetch("HTTP_PROXY", nil)
|
93
90
|
default_config :retry_limit, 3
|
94
91
|
default_config :tenancy, "default"
|
95
92
|
default_config :instance_initiated_shutdown_behavior, nil
|
@@ -194,10 +191,10 @@ module Kitchen
|
|
194
191
|
end
|
195
192
|
|
196
193
|
# empty keys cause failures when tagging and they make no sense
|
197
|
-
validations[:tags] = lambda do |
|
194
|
+
validations[:tags] = lambda do |_attr, val, _driver|
|
198
195
|
# if someone puts the tags each on their own line it's an array not a hash
|
199
196
|
# @todo we should probably just do the right thing and support this format
|
200
|
-
if val.
|
197
|
+
if val.instance_of?(Array)
|
201
198
|
warn "AWS instance tags must be specified as a single hash, not a tag " \
|
202
199
|
"on each line. Example: {:foo => 'bar', :bar => 'foo'}"
|
203
200
|
exit!
|
@@ -247,13 +244,13 @@ module Kitchen
|
|
247
244
|
info("Auto placement on one dedicated host out of: #{hosts_with_capacity.map(&:host_id).join(", ")}")
|
248
245
|
end
|
249
246
|
|
250
|
-
if config[:spot_price]
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
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
|
257
254
|
info("Instance <#{server.id}> requested.")
|
258
255
|
with_request_limit_backoff(state) do
|
259
256
|
logging_proc = ->(attempts) { info("Polling AWS for existence, attempt #{attempts}...") }
|
@@ -269,7 +266,7 @@ module Kitchen
|
|
269
266
|
tries: 10,
|
270
267
|
sleep: lambda { |n| [2**n, 30].min },
|
271
268
|
on: ::Aws::EC2::Errors::InvalidInstanceIDNotFound
|
272
|
-
) do |
|
269
|
+
) do |_r, _|
|
273
270
|
wait_until_ready(server, state)
|
274
271
|
end
|
275
272
|
|
@@ -320,10 +317,10 @@ module Kitchen
|
|
320
317
|
delete_key(state)
|
321
318
|
|
322
319
|
# Clean up dedicated hosts matching instance_type and unused (if allowed)
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
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) }
|
327
324
|
end
|
328
325
|
|
329
326
|
def image
|
@@ -427,7 +424,7 @@ module Kitchen
|
|
427
424
|
def expand_config(conf, key)
|
428
425
|
configs = []
|
429
426
|
|
430
|
-
if conf[key]
|
427
|
+
if conf[key].is_a?(Array)
|
431
428
|
values = conf[key]
|
432
429
|
values.each do |value|
|
433
430
|
new_config = conf.clone
|
@@ -499,11 +496,11 @@ module Kitchen
|
|
499
496
|
instance_data = instance_generator.ec2_instance_data
|
500
497
|
|
501
498
|
config_spot_price = config[:spot_price].to_s
|
502
|
-
if %w{ondemand on-demand}.include?(config_spot_price)
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
499
|
+
spot_price = if %w{ondemand on-demand}.include?(config_spot_price)
|
500
|
+
""
|
501
|
+
else
|
502
|
+
config_spot_price
|
503
|
+
end
|
507
504
|
spot_options = {
|
508
505
|
# Must use one-time in order to use instance_interruption_behavior=terminate
|
509
506
|
# spot_instance_type: "one-time", # default
|
@@ -519,7 +516,7 @@ module Kitchen
|
|
519
516
|
|
520
517
|
instance_data[:instance_market_options] = {
|
521
518
|
market_type: "spot",
|
522
|
-
spot_options
|
519
|
+
spot_options:,
|
523
520
|
}
|
524
521
|
|
525
522
|
# The preferred way to create a spot instance is via request_spot_instances()
|
@@ -551,7 +548,7 @@ module Kitchen
|
|
551
548
|
aws_instance.state.name == "running" &&
|
552
549
|
hostname != "0.0.0.0"
|
553
550
|
|
554
|
-
if ready && (
|
551
|
+
if ready && (hostname.nil? || hostname == "")
|
555
552
|
debug("Unable to detect hostname using interface_type #{config[:interface]}. Fallback to ordered mapping")
|
556
553
|
state[:hostname] = hostname(aws_instance, nil)
|
557
554
|
end
|
@@ -567,7 +564,7 @@ module Kitchen
|
|
567
564
|
output = Base64.decode64(output)
|
568
565
|
debug "Console output: --- \n#{output}"
|
569
566
|
end
|
570
|
-
ready = !!(output
|
567
|
+
ready = !!(output.include?("Windows is Ready to use"))
|
571
568
|
end
|
572
569
|
end
|
573
570
|
ready
|
@@ -600,7 +597,7 @@ module Kitchen
|
|
600
597
|
end
|
601
598
|
|
602
599
|
def fetch_windows_admin_password(server, state)
|
603
|
-
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|
|
604
601
|
enc = server.client.get_password_data(
|
605
602
|
instance_id: state[:server_id]
|
606
603
|
).password_data
|
@@ -655,7 +652,7 @@ module Kitchen
|
|
655
652
|
server.send(interface_type)
|
656
653
|
else
|
657
654
|
potential_hostname = nil
|
658
|
-
INTERFACE_TYPES.
|
655
|
+
INTERFACE_TYPES.each_value do |type|
|
659
656
|
potential_hostname ||= server.send(type)
|
660
657
|
# AWS returns an empty string if the dns name isn't populated yet
|
661
658
|
potential_hostname = nil if potential_hostname == ""
|
@@ -717,7 +714,7 @@ module Kitchen
|
|
717
714
|
|
718
715
|
# Preparing custom static admin user if we defined something other than Administrator
|
719
716
|
custom_admin_script = ""
|
720
|
-
if
|
717
|
+
if instance.transport[:username] !~ /administrator/i && instance.transport[:password]
|
721
718
|
custom_admin_script = Kitchen::Util.outdent!(<<-EOH)
|
722
719
|
"Disabling Complex Passwords" >> $logfile
|
723
720
|
$seccfg = [IO.Path]::GetTempFileName()
|
@@ -759,7 +756,7 @@ module Kitchen
|
|
759
756
|
def image_info(image)
|
760
757
|
root_device = image.block_device_mappings
|
761
758
|
.find { |b| b.device_name == image.root_device_name }
|
762
|
-
volume_type = " #{root_device.ebs.volume_type}" if root_device
|
759
|
+
volume_type = " #{root_device.ebs.volume_type}" if root_device&.ebs
|
763
760
|
|
764
761
|
" Architecture: #{image.architecture}," \
|
765
762
|
" Virtualization: #{image.virtualization_type}," \
|
@@ -813,6 +810,17 @@ module Kitchen
|
|
813
810
|
params = {
|
814
811
|
group_name: "kitchen-#{Array.new(8) { rand(36).to_s(36) }.join}",
|
815
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
|
+
],
|
816
824
|
}
|
817
825
|
params[:vpc_id] = vpc_id if vpc_id
|
818
826
|
resp = ec2.client.create_security_group(params)
|
@@ -829,7 +837,7 @@ module Kitchen
|
|
829
837
|
from_port: port,
|
830
838
|
to_port: port,
|
831
839
|
ip_ranges: Array(config[:security_group_cidr_ip]).map do |cidr_ip|
|
832
|
-
{ cidr_ip:
|
840
|
+
{ cidr_ip: }
|
833
841
|
end,
|
834
842
|
}
|
835
843
|
end
|
@@ -851,14 +859,28 @@ module Kitchen
|
|
851
859
|
(Etc.getlogin || "nologin").gsub(/\W/, ""),
|
852
860
|
Socket.gethostname.gsub(/\W/, "")[0..20],
|
853
861
|
Time.now.utc.iso8601,
|
854
|
-
Array.new(8) { rand(36).to_s(36) }.join
|
862
|
+
Array.new(8) { rand(36).to_s(36) }.join,
|
855
863
|
]
|
856
864
|
# In a perfect world this would generate the key locally and use ImportKey
|
857
865
|
# instead for better security, but given the use case that is very likely
|
858
866
|
# to rapidly exhaust local entropy by creating a lot of keys. So this is
|
859
867
|
# probably fine. If you want very high security, probably don't use this
|
860
868
|
# feature anyway.
|
861
|
-
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
|
+
)
|
862
884
|
state[:auto_key_id] = resp.key_name
|
863
885
|
info("Created automatic key pair #{state[:auto_key_id]}")
|
864
886
|
# Write the key out with safe permissions
|
@@ -892,7 +914,7 @@ module Kitchen
|
|
892
914
|
puts "ENI #{config[:elastic_network_interface_id]} already attached."
|
893
915
|
end
|
894
916
|
rescue ::Aws::EC2::Errors::InvalidNetworkInterfaceIDNotFound => e
|
895
|
-
warn(
|
917
|
+
warn(e.to_s)
|
896
918
|
end
|
897
919
|
end
|
898
920
|
|
@@ -922,7 +944,6 @@ module Kitchen
|
|
922
944
|
state.delete(:auto_key_id)
|
923
945
|
File.unlink("#{config[:kitchen_root]}/.kitchen/#{instance.name}.pem")
|
924
946
|
end
|
925
|
-
|
926
947
|
end
|
927
948
|
end
|
928
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.18.0
|
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-28 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: []
|
@@ -110,7 +110,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
110
110
|
- !ruby/object:Gem::Version
|
111
111
|
version: '0'
|
112
112
|
requirements: []
|
113
|
-
rubygems_version: 3.4.
|
113
|
+
rubygems_version: 3.4.10
|
114
114
|
signing_key:
|
115
115
|
specification_version: 4
|
116
116
|
summary: A Test Kitchen Driver for Amazon EC2
|