kitchen-ec2 3.17.0 → 3.17.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a4993e5b97ddbe3fb98f8e58b9877bf90b3e0a165b521dc295d53dc9bcbbe192
4
- data.tar.gz: 621bf0ddd53d9f8488ca6b7c351cf12c733cbcc534f23c30a3390b932fdc2e4e
3
+ metadata.gz: abdd51753a33ae7cf21aeb7f3073cd949d0c0c998eb065955b2bb8982441760a
4
+ data.tar.gz: f8a5ffd49f6213cc5822857f2af830be06fd42fe1c9a29cb60328b0fd4835e45
5
5
  SHA512:
6
- metadata.gz: f62f3a41a041935cd4371e0cef514ec1a919f40ea8e21dc25bb84cec67dce7d97810469a3e220cc567daff040ba37da5cb026ddcb94aba0bdf86eec5adcffe6c
7
- data.tar.gz: 7011bf26dc6e011af1af506b7ce9c42d5c26e1a19ff610896ed407200490d473b467dbf80a1260868e160e8d48da6792a1e0343dc5792eff2dbc09c7cee663fc
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: region,
39
+ region:,
44
40
  profile: profile_name,
45
- http_proxy: http_proxy,
46
- ssl_verify_peer: ssl_verify_peer
41
+ http_proxy:,
42
+ ssl_verify_peer:
47
43
  )
48
- ::Aws.config.update(retry_limit: retry_limit) unless retry_limit.nil?
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
- unless response.unsuccessful.empty?
102
- warn "ERROR: Could not release dedicated host #{host_id}. Host may remain allocated and incur cost"
103
- exit!
104
- end
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 # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
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: tags }
133
- volume_tag_spec = { resource_type: "volume", tags: 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: 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: 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
@@ -40,10 +40,10 @@ module Kitchen
40
40
  end
41
41
 
42
42
  def self.from_image(driver, image)
43
- if /AlmaLinux OS/i.match?(image.name)
44
- image.name =~ /\b(\d+(\.\d+)?)\b/i
45
- new(driver, "alma", (Regexp.last_match || [])[1], image.architecture)
46
- end
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
- if /amzn-ami/i.match?(image.name)
43
- image.name =~ /\b(\d+(\.\d+[\.\d])?)/i
44
- new(driver, "amazon", (Regexp.last_match || [])[1], image.architecture)
45
- end
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
- if /amzn2-ami/i.match?(image.name)
43
- image.name =~ /\b(\d+(\.\d+[\.\d])?)/i
44
- new(driver, "amazon2", (Regexp.last_match || [])[1], image.architecture)
45
- end
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
- if /al2023-ami/i.match?(image.name)
43
- image.name =~ /\b(\d+(\.\d+[\.\d])?)/i
44
- new(driver, "amazon2023", (Regexp.last_match || [])[1], image.architecture)
45
- end
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
- if /centos/i.match?(image.name)
56
- image.name =~ /\b(\d+(\.\d+)?)\b/i
57
- new(driver, "centos", (Regexp.last_match || [])[1], image.architecture)
58
- end
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
- if /debian/i.match?(image.name)
77
- image.name =~ /\b(\d+|#{DEBIAN_CODENAMES.values.join("|")})\b/i
78
- version = (Regexp.last_match || [])[1]
79
- if version && version.to_i == 0
80
- version = DEBIAN_CODENAMES.find do |_v, codename|
81
- codename == version.downcase
82
- end.first
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
- if /fedora/i.match?(image.name)
43
- image.name =~ /\b(\d+(\.\d+)?)\b/i
44
- new(driver, "fedora", (Regexp.last_match || [])[1], image.architecture)
45
- end
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
- if /freebsd/i.match?(image.name)
45
- image.name =~ /\b(\d+(\.\d+)?)\b/i
46
- new(driver, "freebsd", (Regexp.last_match || [])[1], image.architecture)
47
- end
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
- if /amzn-ec2-macos/i.match?(image.name)
43
- image.name =~ /\b(\d+(\.\d+[\.\d])?)/i
44
- new(driver, "macos", (Regexp.last_match || [])[1], image.architecture)
45
- end
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
- (version && version.to_f < 6.4) ? "root" : "ec2-user"
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
- if /rhel/i.match?(image.name)
49
- image.name =~ /\b(\d+(\.\d+)?)/i
50
- new(driver, "rhel", (Regexp.last_match || [])[1], image.architecture)
51
- end
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
- if /Rocky-/i.match?(image.name)
43
- image.name =~ /\b(\d+(\.\d+[\.\d])?)/i
44
- new(driver, "rocky", (Regexp.last_match || [])[1], image.architecture)
45
- end
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
- if /ubuntu/i.match?(image.name)
43
- image.name =~ /\b(\d+(\.\d+)?)\b/i
44
- new(driver, "ubuntu", (Regexp.last_match || [])[1], image.architecture)
45
- end
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
- if /Windows/i.match?(image.name)
74
- # 2008 R2 SP2
75
- if image.name =~ /(\b\d+)\W*(r\d+)?/i
76
- major, revision = (Regexp.last_match || [])[1], (Regexp.last_match || [])[2]
77
- if image.name =~ /(sp\d+|rtm)/i
78
- service_pack = (Regexp.last_match || [])[1]
79
- end
80
- revision = revision.downcase if revision
81
- service_pack ||= "rtm"
82
- service_pack = service_pack.downcase
83
- version = "#{major}#{revision}#{service_pack}"
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 # rubocop:disable Metrics/MethodLength
134
+ def windows_name_filter
136
135
  major, revision, service_pack = windows_version_parts
137
- if major == 2022 || major == 2019 || major == 2016
136
+ if [2022, 2019, 2016].include?(major)
138
137
  "Windows_Server-#{major}-English-Full-Base-*"
139
- elsif major == 1709 || major == 1803
138
+ elsif [1709, 1803].include?(major)
140
139
  "Windows_Server-#{major}-English-Core-ContainersLatest-*"
141
140
  else
142
- case revision
143
- when nil
144
- revision_strings = ["", "R*_"]
145
- when 0
146
- revision_strings = [""]
147
- else
148
- revision_strings = ["R#{revision}_"]
149
- end
150
-
151
- case service_pack
152
- when nil
153
- revision_strings = revision_strings.flat_map { |r| ["#{r}RTM", "#{r}SP*"] }
154
- when 0
155
- revision_strings = revision_strings.map { |r| "#{r}RTM" }
156
- else
157
- revision_strings = revision_strings.map { |r| "#{r}SP#{service_pack}" }
158
- end
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: 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 && images.first.id
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
- if platform && platforms[platform]
140
- platforms[platform].new(driver, platform, version, architecture)
141
- end
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 && %w{gp3 gp2}.any? { |t| b.ebs.volume_type == t }
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)
@@ -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["AWS_PROFILE"]
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["AWS_SSH_KEY_ID"]
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["HTTP_PROXY"]
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 |attr, val, _driver|
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.class == Array
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
- # Spot instance when a price is set
252
- server = with_request_limit_backoff(state) { submit_spots }
253
- else
254
- # On-demand instance
255
- server = with_request_limit_backoff(state) { submit_server }
256
- end
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 |r, _|
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
- if config[:tenancy] == "host" && allow_deallocate_host?
324
- empty_hosts = hosts_with_capacity.select { |host| host_unused?(host) }
325
- empty_hosts.each { |host| deallocate_host(host.host_id) }
326
- end
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] && conf[key].is_a?(Array)
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
- spot_price = ""
504
- else
505
- spot_price = config_spot_price
506
- end
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: 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 && ( hostname.nil? || hostname == "" )
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 =~ /Windows is Ready to use/)
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 |aws_instance|
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.values.each do |type|
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 !(instance.transport[:username] =~ /administrator/i) && instance.transport[:password]
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 && root_device.ebs
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: 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(key_name: "kitchen-#{name_parts.join("-")}", key_type: config[:aws_ssh_key_type])
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("#{e}")
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
@@ -17,10 +17,8 @@
17
17
  # limitations under the License.
18
18
 
19
19
  module Kitchen
20
-
21
20
  module Driver
22
-
23
21
  # Version string for EC2 Test Kitchen driver
24
- EC2_VERSION = "3.17.0".freeze
22
+ EC2_VERSION = "3.17.1".freeze
25
23
  end
26
24
  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.17.0
4
+ version: 3.17.1
5
5
  platform: ruby
6
6
  authors:
7
- - Fletcher Nichol
7
+ - Test Kitchen Team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-06-14 00:00:00.000000000 Z
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
- - fnichol@nichol.ca
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.12
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