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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a4993e5b97ddbe3fb98f8e58b9877bf90b3e0a165b521dc295d53dc9bcbbe192
4
- data.tar.gz: 621bf0ddd53d9f8488ca6b7c351cf12c733cbcc534f23c30a3390b932fdc2e4e
3
+ metadata.gz: 5a5e24ca8e2d208d63f7079597ea3d8c3773eab8d82891ec1052f226dfb0d3b2
4
+ data.tar.gz: 6bd3c4846bc622f399ee748e2e5e15d5aaf1dc2b70d8db875ac3d20897fdb58e
5
5
  SHA512:
6
- metadata.gz: f62f3a41a041935cd4371e0cef514ec1a919f40ea8e21dc25bb84cec67dce7d97810469a3e220cc567daff040ba37da5cb026ddcb94aba0bdf86eec5adcffe6c
7
- data.tar.gz: 7011bf26dc6e011af1af506b7ce9c42d5c26e1a19ff610896ed407200490d473b467dbf80a1260868e160e8d48da6792a1e0343dc5792eff2dbc09c7cee663fc
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: 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,44 @@ 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: }
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
- 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.18.0".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.18.0
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-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
- - 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