kitchen-vagrant 2.2.1 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/kitchen/driver/helpers.rb +101 -6
- data/lib/kitchen/driver/vagrant.rb +156 -41
- data/lib/kitchen/driver/vagrant_version.rb +2 -1
- data/templates/Vagrantfile.erb +3 -1
- metadata +17 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: cf0fbd431e7e5a52a144f6ce2e79edea1d2783c74c0ef212c3674a12e147683e
|
|
4
|
+
data.tar.gz: fdde8621c74520cf97a5367bfa3098aedc814d8037ad564ef8cada2056237807
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1877e0240f40b4d4880ba3032f9801a984252051a88ba2a8fc0bd5af9d314ac5aa701b1116e9df747614b6ca3adacbbf898be6fdfe1d3d104f41f2321d2aceaa
|
|
7
|
+
data.tar.gz: eef20bc7471c539f0b11cbb31d80337bf7037905e7a1fecc9f7104d9b9335f57bd5d5437e376bb19942d5e80dcffb5193ba5ddab7836d8c3cb315aced9149361
|
|
@@ -15,30 +15,90 @@
|
|
|
15
15
|
# See the License for the specific language governing permissions and
|
|
16
16
|
# limitations under the License.
|
|
17
17
|
|
|
18
|
+
require "base64" unless defined?(Base64)
|
|
18
19
|
require "mixlib/shellout" unless defined?(Mixlib::ShellOut)
|
|
19
20
|
require "fileutils" unless defined?(FileUtils)
|
|
20
21
|
require "json" unless defined?(JSON)
|
|
21
22
|
|
|
22
23
|
module Kitchen
|
|
24
|
+
# Test Kitchen driver plugins.
|
|
23
25
|
module Driver
|
|
26
|
+
# Helpers for talking to Hyper-V from the Vagrant driver.
|
|
27
|
+
#
|
|
28
|
+
# Hyper-V has no command line interface of its own, so everything here
|
|
29
|
+
# funnels through PowerShell: a script is wrapped so that it dot-sources
|
|
30
|
+
# the bundled `support/hyperv.ps1`, base64-encoded for `-EncodedCommand`
|
|
31
|
+
# (which sidesteps all shell quoting problems), executed, and its JSON
|
|
32
|
+
# output parsed back into Ruby.
|
|
33
|
+
#
|
|
34
|
+
# The module expects to be mixed into a {Kitchen::Configurable} that also
|
|
35
|
+
# provides {Kitchen::Logging}, which the Vagrant driver does.
|
|
36
|
+
#
|
|
37
|
+
# @author Steven Murawski <smurawski@chef.io>
|
|
24
38
|
module HypervHelpers
|
|
39
|
+
# Encodes a PowerShell script for `powershell.exe -EncodedCommand`.
|
|
40
|
+
#
|
|
41
|
+
# PowerShell requires UTF-16LE, not UTF-8, and strict (unwrapped) base64.
|
|
42
|
+
#
|
|
43
|
+
# @param script [String] a PowerShell script
|
|
44
|
+
# @return [String] the script as single-line base64
|
|
45
|
+
# @api private
|
|
25
46
|
def encode_command(script)
|
|
26
47
|
encoded_script = script.encode("UTF-16LE", "UTF-8")
|
|
27
48
|
Base64.strict_encode64(encoded_script)
|
|
28
49
|
end
|
|
29
50
|
|
|
51
|
+
# The processor architecture Windows reports for this process.
|
|
52
|
+
#
|
|
53
|
+
# `PROCESSOR_ARCHITEW6432` is only set for a 32-bit process running under
|
|
54
|
+
# WOW64, where it holds the *machine's* architecture while
|
|
55
|
+
# `PROCESSOR_ARCHITECTURE` holds the emulated one -- so it wins when
|
|
56
|
+
# present.
|
|
57
|
+
#
|
|
58
|
+
# @return [String,nil] e.g. `"AMD64"`, or nil off Windows
|
|
59
|
+
# @api private
|
|
60
|
+
def os_architecture
|
|
61
|
+
ENV["PROCESSOR_ARCHITEW6432"] || ENV["PROCESSOR_ARCHITECTURE"]
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Whether the running Ruby is a 64-bit build, determined from the size of
|
|
65
|
+
# a packed pointer.
|
|
66
|
+
#
|
|
67
|
+
# @return [true,false] whether this Ruby is 64-bit
|
|
68
|
+
# @api private
|
|
69
|
+
def ruby_64bit?
|
|
70
|
+
["foo"].pack("p").size != 4
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Whether both the OS and the running Ruby are 64-bit.
|
|
74
|
+
#
|
|
75
|
+
# @return [true,false] whether this is a 64-bit Ruby on a 64-bit Windows
|
|
76
|
+
# @api private
|
|
30
77
|
def is_64bit?
|
|
31
|
-
|
|
32
|
-
ruby_arch = ["foo"].pack("p").size == 4 ? 32 : 64
|
|
33
|
-
os_arch == "AMD64" && ruby_arch == 64
|
|
78
|
+
os_architecture == "AMD64" && ruby_64bit?
|
|
34
79
|
end
|
|
35
80
|
|
|
81
|
+
# Whether both the OS and the running Ruby are 32-bit.
|
|
82
|
+
#
|
|
83
|
+
# Note this is deliberately *not* the negation of {#is_64bit?}: a 32-bit
|
|
84
|
+
# Ruby on a 64-bit Windows (the WOW64 case) is neither.
|
|
85
|
+
#
|
|
86
|
+
# @return [true,false] whether this is a 32-bit Ruby on a 32-bit Windows
|
|
87
|
+
# @api private
|
|
36
88
|
def is_32bit?
|
|
37
|
-
|
|
38
|
-
ruby_arch = ["foo"].pack("p").size == 4 ? 32 : 64
|
|
39
|
-
os_arch != "AMD64" && ruby_arch == 32
|
|
89
|
+
os_architecture != "AMD64" && !ruby_64bit?
|
|
40
90
|
end
|
|
41
91
|
|
|
92
|
+
# Path to a PowerShell that matches the machine's architecture.
|
|
93
|
+
#
|
|
94
|
+
# When Ruby and Windows agree on bitness, the real `System32` PowerShell
|
|
95
|
+
# is correct. When they disagree -- a 32-bit Ruby on 64-bit Windows --
|
|
96
|
+
# `System32` would be silently redirected by WOW64 to the 32-bit
|
|
97
|
+
# PowerShell, which cannot see the Hyper-V cmdlets; `Sysnative` is the
|
|
98
|
+
# alias that reaches the 64-bit one.
|
|
99
|
+
#
|
|
100
|
+
# @return [String] absolute path to powershell.exe
|
|
101
|
+
# @api private
|
|
42
102
|
def powershell_64_bit
|
|
43
103
|
if is_64bit? || is_32bit?
|
|
44
104
|
'c:\windows\system32\windowspowershell\v1.0\powershell.exe'
|
|
@@ -47,6 +107,12 @@ module Kitchen
|
|
|
47
107
|
end
|
|
48
108
|
end
|
|
49
109
|
|
|
110
|
+
# Builds a full `powershell.exe` command line that dot-sources the gem's
|
|
111
|
+
# `support/hyperv.ps1` helper functions and then runs `script`.
|
|
112
|
+
#
|
|
113
|
+
# @param script [String] a PowerShell script
|
|
114
|
+
# @return [String] a command line ready to hand to a shell
|
|
115
|
+
# @api private
|
|
50
116
|
def wrap_command(script)
|
|
51
117
|
base_script_path = File.join(File.dirname(__FILE__), "/../../../support/hyperv.ps1")
|
|
52
118
|
debug("Loading functions from #{base_script_path}")
|
|
@@ -60,6 +126,7 @@ module Kitchen
|
|
|
60
126
|
#
|
|
61
127
|
# @param cmd [String] command to run locally
|
|
62
128
|
# @param options [Hash] options hash
|
|
129
|
+
# @return [Hash,nil] the parsed JSON the script emitted, if any
|
|
63
130
|
# @see Kitchen::ShellOut.run_command
|
|
64
131
|
# @api private
|
|
65
132
|
def run_ps(cmd, options = {})
|
|
@@ -70,6 +137,13 @@ module Kitchen
|
|
|
70
137
|
execute_command wrapped_command, options
|
|
71
138
|
end
|
|
72
139
|
|
|
140
|
+
# Runs a command locally and parses its output as JSON.
|
|
141
|
+
#
|
|
142
|
+
# @param cmd [String] command to run locally
|
|
143
|
+
# @param options [Hash] options passed through to `Mixlib::ShellOut`
|
|
144
|
+
# @return [Hash,Array,nil] the parsed output, or nil if there was none
|
|
145
|
+
# @raise [RuntimeError] if the command exited non-zero
|
|
146
|
+
# @api private
|
|
73
147
|
def execute_command(cmd, options = {})
|
|
74
148
|
debug("#Local Command BEGIN (#{cmd})")
|
|
75
149
|
sh = Mixlib::ShellOut.new(cmd, options)
|
|
@@ -81,10 +155,21 @@ module Kitchen
|
|
|
81
155
|
JSON.parse(stdout) if stdout.length > 2
|
|
82
156
|
end
|
|
83
157
|
|
|
158
|
+
# Strips the interactive prompt lines PowerShell interleaves with real
|
|
159
|
+
# output, which would otherwise make the result unparseable as JSON.
|
|
160
|
+
#
|
|
161
|
+
# @param stdout [String] raw standard output
|
|
162
|
+
# @return [String] output with `PS ...>` lines removed
|
|
163
|
+
# @api private
|
|
84
164
|
def sanitize_stdout(stdout)
|
|
85
165
|
stdout.split("\n").select { |s| !s.start_with?("PS") }.join("\n")
|
|
86
166
|
end
|
|
87
167
|
|
|
168
|
+
# Asks Hyper-V for the virtual switch new VMs should be attached to.
|
|
169
|
+
#
|
|
170
|
+
# @return [String] the name of the switch
|
|
171
|
+
# @raise [RuntimeError] if no usable switch could be determined
|
|
172
|
+
# @api private
|
|
88
173
|
def hyperv_switch
|
|
89
174
|
default_switch_object = run_ps hyperv_default_switch_ps
|
|
90
175
|
if default_switch_object.nil? ||
|
|
@@ -96,6 +181,11 @@ module Kitchen
|
|
|
96
181
|
default_switch_object["Name"]
|
|
97
182
|
end
|
|
98
183
|
|
|
184
|
+
# The PowerShell that {#hyperv_switch} runs. Honours
|
|
185
|
+
# `KITCHEN_HYPERV_SWITCH`; without it, `Get-DefaultVMSwitch` picks one.
|
|
186
|
+
#
|
|
187
|
+
# @return [String] a PowerShell script emitting a JSON switch object
|
|
188
|
+
# @api private
|
|
99
189
|
def hyperv_default_switch_ps
|
|
100
190
|
<<-VMSWITCH
|
|
101
191
|
Get-DefaultVMSwitch #{ENV["KITCHEN_HYPERV_SWITCH"]} | ConvertTo-Json
|
|
@@ -104,6 +194,11 @@ module Kitchen
|
|
|
104
194
|
|
|
105
195
|
private
|
|
106
196
|
|
|
197
|
+
# Renders a Ruby Array as a PowerShell array literal.
|
|
198
|
+
#
|
|
199
|
+
# @param list [Array,nil] the values to render
|
|
200
|
+
# @return [String] e.g. `@("a", "b")`, or `@()` when empty
|
|
201
|
+
# @api private
|
|
107
202
|
def ruby_array_to_ps_array(list)
|
|
108
203
|
return "@()" if list.nil? || list.empty?
|
|
109
204
|
|
|
@@ -127,6 +127,11 @@ module Kitchen
|
|
|
127
127
|
info("Vagrant instance #{instance.to_str} created.")
|
|
128
128
|
end
|
|
129
129
|
|
|
130
|
+
# The box this Instance should use when the user has not named one.
|
|
131
|
+
#
|
|
132
|
+
# Platforms the Bento project builds are mapped onto their `bento/`
|
|
133
|
+
# box; anything else is assumed to name a box directly.
|
|
134
|
+
#
|
|
130
135
|
# @return [String,nil] the Vagrant box for this Instance
|
|
131
136
|
def default_box
|
|
132
137
|
if bento_box?(instance.platform.name)
|
|
@@ -136,6 +141,11 @@ module Kitchen
|
|
|
136
141
|
end
|
|
137
142
|
end
|
|
138
143
|
|
|
144
|
+
# The box URL this Instance should use when the user has not named one.
|
|
145
|
+
#
|
|
146
|
+
# Always nil: modern Vagrant resolves boxes through Vagrant Cloud, so an
|
|
147
|
+
# explicit URL is only needed for privately hosted boxes.
|
|
148
|
+
#
|
|
139
149
|
# @return [String,nil] the Vagrant box URL for this Instance
|
|
140
150
|
def default_box_url
|
|
141
151
|
nil
|
|
@@ -157,6 +167,12 @@ module Kitchen
|
|
|
157
167
|
state.delete(:hostname)
|
|
158
168
|
end
|
|
159
169
|
|
|
170
|
+
# Packages a created instance into a redistributable `.box` file in the
|
|
171
|
+
# current working directory, then destroys the instance.
|
|
172
|
+
#
|
|
173
|
+
# @param state [Hash] mutable instance state
|
|
174
|
+
# @raise [UserError] if the instance has not been created
|
|
175
|
+
# @raise [ActionFailed] if the action could not be completed
|
|
160
176
|
def package(state)
|
|
161
177
|
if state[:hostname].nil?
|
|
162
178
|
raise UserError, "Vagrant instance not created!"
|
|
@@ -216,9 +232,11 @@ module Kitchen
|
|
|
216
232
|
instance.transport.name.downcase =~ /win_?rm/
|
|
217
233
|
end
|
|
218
234
|
|
|
219
|
-
#
|
|
220
|
-
#
|
|
221
|
-
#
|
|
235
|
+
# The guest-side directory that the host's omnibus package cache should
|
|
236
|
+
# be shared into, so repeated converges do not re-download packages.
|
|
237
|
+
#
|
|
238
|
+
# @return [String,false] the guest path, or false if caching does not
|
|
239
|
+
# apply to this box and provider combination
|
|
222
240
|
def cache_directory
|
|
223
241
|
if enable_cache?
|
|
224
242
|
config[:cache_directory]
|
|
@@ -229,7 +247,10 @@ module Kitchen
|
|
|
229
247
|
|
|
230
248
|
protected
|
|
231
249
|
|
|
250
|
+
# Where users are pointed when Vagrant is missing or too old.
|
|
232
251
|
WEBSITE = "https://developer.hashicorp.com/vagrant/install".freeze
|
|
252
|
+
|
|
253
|
+
# The oldest Vagrant this driver supports.
|
|
233
254
|
MIN_VER = "2.4.0".freeze
|
|
234
255
|
|
|
235
256
|
class << self
|
|
@@ -238,10 +259,11 @@ module Kitchen
|
|
|
238
259
|
attr_accessor :vagrant_version
|
|
239
260
|
end
|
|
240
261
|
|
|
241
|
-
#
|
|
262
|
+
# Returns whether or not a platform name could have a corresponding Bento
|
|
242
263
|
# box produced by the Bento project.
|
|
243
264
|
# (https://github.com/chef/bento).
|
|
244
265
|
#
|
|
266
|
+
# @param name [String] a Test Kitchen platform name
|
|
245
267
|
# @return [TrueClass,FalseClass] whether or not the name could be a Bento
|
|
246
268
|
# box
|
|
247
269
|
# @api private
|
|
@@ -250,8 +272,13 @@ module Kitchen
|
|
|
250
272
|
end
|
|
251
273
|
|
|
252
274
|
# Returns whether or not the we expect the box to work with shared folders
|
|
253
|
-
# by matching against a whitelist of bento boxes
|
|
254
|
-
#
|
|
275
|
+
# by matching against a whitelist of bento boxes.
|
|
276
|
+
#
|
|
277
|
+
# Providers without usable shared folder support are excluded outright,
|
|
278
|
+
# whatever the box.
|
|
279
|
+
#
|
|
280
|
+
# @param box [String] the Vagrant box name
|
|
281
|
+
# @return [TrueClass,FalseClass] whether or not the box should work with
|
|
255
282
|
# shared folders
|
|
256
283
|
# @api private
|
|
257
284
|
def safe_share?(box)
|
|
@@ -261,7 +288,11 @@ module Kitchen
|
|
|
261
288
|
end
|
|
262
289
|
|
|
263
290
|
# Return true if we found the criteria to enable the cache_directory
|
|
264
|
-
# functionality
|
|
291
|
+
# functionality.
|
|
292
|
+
#
|
|
293
|
+
# @return [TrueClass,FalseClass] whether the package cache should be
|
|
294
|
+
# shared into the guest
|
|
295
|
+
# @api private
|
|
265
296
|
def enable_cache?
|
|
266
297
|
return false unless config[:cache_directory]
|
|
267
298
|
return true if safe_share?(config[:box])
|
|
@@ -271,8 +302,10 @@ module Kitchen
|
|
|
271
302
|
false
|
|
272
303
|
end
|
|
273
304
|
|
|
274
|
-
# Renders and writes out a Vagrantfile dedicated to this instance.
|
|
305
|
+
# Renders and writes out a Vagrantfile dedicated to this instance. A
|
|
306
|
+
# no-op if this action has already written one.
|
|
275
307
|
#
|
|
308
|
+
# @return [void]
|
|
276
309
|
# @api private
|
|
277
310
|
def create_vagrantfile
|
|
278
311
|
return if @vagrantfile_created
|
|
@@ -288,6 +321,7 @@ module Kitchen
|
|
|
288
321
|
# Logs the Vagrantfile's contents to the debug log level.
|
|
289
322
|
#
|
|
290
323
|
# @param vagrantfile [String] path to the Vagrantfile
|
|
324
|
+
# @return [void]
|
|
291
325
|
# @api private
|
|
292
326
|
def debug_vagrantfile(vagrantfile)
|
|
293
327
|
return unless logger.debug?
|
|
@@ -297,8 +331,10 @@ module Kitchen
|
|
|
297
331
|
debug("------------")
|
|
298
332
|
end
|
|
299
333
|
|
|
300
|
-
#
|
|
334
|
+
# Expands `:box_download_ca_cert` relative to the kitchen root, so a
|
|
335
|
+
# `.kitchen.yml` can refer to a cert alongside itself.
|
|
301
336
|
#
|
|
337
|
+
# @return [void]
|
|
302
338
|
# @api private
|
|
303
339
|
def finalize_ca_cert!
|
|
304
340
|
unless config[:box_download_ca_cert].nil?
|
|
@@ -308,9 +344,14 @@ module Kitchen
|
|
|
308
344
|
end
|
|
309
345
|
end
|
|
310
346
|
|
|
311
|
-
#
|
|
347
|
+
# Replaces a truthy `:box_auto_update` with the `vagrant box update`
|
|
348
|
+
# command line that {#run_box_auto_update} should run. A falsey value is
|
|
349
|
+
# left alone so that `box_auto_update: false` stays disabled.
|
|
350
|
+
#
|
|
351
|
+
# @return [void]
|
|
352
|
+
# @api private
|
|
312
353
|
def finalize_box_auto_update!
|
|
313
|
-
return
|
|
354
|
+
return unless config[:box_auto_update]
|
|
314
355
|
|
|
315
356
|
cmd = "#{config[:vagrant_binary]} box update --box #{config[:box]}"
|
|
316
357
|
cmd += " --architecture #{config[:box_arch]}" if config[:box_arch]
|
|
@@ -319,9 +360,14 @@ module Kitchen
|
|
|
319
360
|
config[:box_auto_update] = cmd
|
|
320
361
|
end
|
|
321
362
|
|
|
322
|
-
#
|
|
363
|
+
# Replaces a truthy `:box_auto_prune` with the `vagrant box prune`
|
|
364
|
+
# command line that {#run_box_auto_prune} should run. A falsey value is
|
|
365
|
+
# left alone so that `box_auto_prune: false` stays disabled.
|
|
366
|
+
#
|
|
367
|
+
# @return [void]
|
|
368
|
+
# @api private
|
|
323
369
|
def finalize_box_auto_prune!
|
|
324
|
-
return
|
|
370
|
+
return unless config[:box_auto_prune]
|
|
325
371
|
|
|
326
372
|
cmd = "#{config[:vagrant_binary]} box prune --force --keep-active-boxes --name #{config[:box]}"
|
|
327
373
|
cmd += " --provider #{config[:provider]}" if config[:provider]
|
|
@@ -357,8 +403,26 @@ module Kitchen
|
|
|
357
403
|
end
|
|
358
404
|
end
|
|
359
405
|
|
|
360
|
-
#
|
|
406
|
+
# Formats network options for use in the Vagrantfile.
|
|
407
|
+
#
|
|
408
|
+
# Accepts either a Hash (rendered as Ruby keyword syntax) or a String
|
|
409
|
+
# (passed through as-is, which is what {#finalize_network!} produces).
|
|
410
|
+
#
|
|
411
|
+
# @param options [Hash,String,#to_s] network options
|
|
412
|
+
# @return [String] formatted options string for Vagrantfile
|
|
413
|
+
# @api private
|
|
414
|
+
def format_network_options(options)
|
|
415
|
+
return options if options.is_a?(String)
|
|
416
|
+
return options.map { |k, v| "#{k}: #{v.inspect}" }.join(", ") if options.is_a?(Hash)
|
|
417
|
+
|
|
418
|
+
options.to_s
|
|
419
|
+
end
|
|
420
|
+
|
|
421
|
+
# Normalises every `:synced_folders` entry: expands the host path
|
|
422
|
+
# against the kitchen root, substitutes `%{instance_name}` tokens, and
|
|
423
|
+
# formats the options for the template.
|
|
361
424
|
#
|
|
425
|
+
# @return [void]
|
|
362
426
|
# @api private
|
|
363
427
|
def finalize_synced_folders!
|
|
364
428
|
config[:synced_folders] = config[:synced_folders]
|
|
@@ -375,9 +439,11 @@ module Kitchen
|
|
|
375
439
|
add_extra_synced_folders!
|
|
376
440
|
end
|
|
377
441
|
|
|
378
|
-
#
|
|
379
|
-
#
|
|
380
|
-
#
|
|
442
|
+
# Shares the host's omnibus package cache into the guest so a converge
|
|
443
|
+
# does not re-download packages it already has.
|
|
444
|
+
#
|
|
445
|
+
# @return [void]
|
|
446
|
+
# @api private
|
|
381
447
|
def add_extra_synced_folders!
|
|
382
448
|
if cache_directory
|
|
383
449
|
FileUtils.mkdir_p(local_kitchen_cache)
|
|
@@ -389,9 +455,12 @@ module Kitchen
|
|
|
389
455
|
end
|
|
390
456
|
end
|
|
391
457
|
|
|
392
|
-
# Truncates
|
|
393
|
-
#
|
|
458
|
+
# Truncates an over-long `:vm_hostname` on Windows guests, where the
|
|
459
|
+
# NetBIOS name is capped at 15 characters. The final character of the
|
|
460
|
+
# original is kept as a suffix so that names which differ only in their
|
|
461
|
+
# tail do not collapse onto each other.
|
|
394
462
|
#
|
|
463
|
+
# @return [void]
|
|
395
464
|
# @api private
|
|
396
465
|
def finalize_vm_hostname!
|
|
397
466
|
string = config[:vm_hostname]
|
|
@@ -401,17 +470,20 @@ module Kitchen
|
|
|
401
470
|
end
|
|
402
471
|
end
|
|
403
472
|
|
|
404
|
-
#
|
|
405
|
-
#
|
|
406
|
-
#
|
|
473
|
+
# Gives a Hyper-V instance a default `public_network` bridged onto the
|
|
474
|
+
# switch named by `KITCHEN_HYPERV_SWITCH`, or whichever switch
|
|
475
|
+
# {HypervHelpers#hyperv_switch} considers best. Instances that already
|
|
476
|
+
# configure a network, and every other provider, are left alone.
|
|
477
|
+
#
|
|
478
|
+
# @return [void]
|
|
407
479
|
# @api private
|
|
408
480
|
def finalize_network!
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
481
|
+
return unless config[:provider] == "hyperv" && config[:network].empty?
|
|
482
|
+
|
|
483
|
+
# Deliberately a new Array rather than a push: `default_config` hands
|
|
484
|
+
# every instance the *same* Array object, so mutating it in place would
|
|
485
|
+
# leak this network into every other instance in the process.
|
|
486
|
+
config[:network] = [["public_network", %{bridge: "#{hyperv_switch}"}]]
|
|
415
487
|
end
|
|
416
488
|
|
|
417
489
|
# Renders the Vagrantfile ERb template.
|
|
@@ -454,6 +526,9 @@ module Kitchen
|
|
|
454
526
|
# any bundler environment should we detect one. Otherwise, subcommands
|
|
455
527
|
# will inherit our bundled environment.
|
|
456
528
|
# @see https://github.com/test-kitchen/kitchen-vagrant/issues/190
|
|
529
|
+
# @param cmd [String] command to run locally
|
|
530
|
+
# @param options [Hash] options hash
|
|
531
|
+
# @return [String] the standard output of the command
|
|
457
532
|
# @see Kitchen::ShellOut#run_command
|
|
458
533
|
# rubocop:disable Metrics/CyclomaticComplexity
|
|
459
534
|
def run_command(cmd, options = {})
|
|
@@ -479,10 +554,10 @@ module Kitchen
|
|
|
479
554
|
# is passed to a windows process with a PATH, Vagrant's batch installer
|
|
480
555
|
# (https://github.com/mitchellh/vagrant-installers/blob/master/substrate
|
|
481
556
|
# /modules/vagrant_installer/templates/windows_vagrant.bat.erb)
|
|
482
|
-
# does not
|
|
557
|
+
# does not effectively prepend the vagrant ruby path in a persistent
|
|
483
558
|
# manner which causes vagrant to use the same ruby as test-kitchen and
|
|
484
559
|
# then the environment is essentially corrupted leading to many errors
|
|
485
|
-
# and
|
|
560
|
+
# and despair
|
|
486
561
|
unless windows_host?
|
|
487
562
|
gem_home = ENV["GEM_HOME"]
|
|
488
563
|
if gem_home && (env["PATH"] || ENV["PATH"])
|
|
@@ -496,8 +571,11 @@ module Kitchen
|
|
|
496
571
|
end
|
|
497
572
|
# rubocop:enable Metrics/CyclomaticComplexity
|
|
498
573
|
|
|
499
|
-
# Check if a newer version of the vagrant box is available and warn the
|
|
574
|
+
# Check if a newer version of the vagrant box is available and warn the
|
|
575
|
+
# user. Skipped when `:box_auto_update` is on, since the update happens
|
|
576
|
+
# regardless.
|
|
500
577
|
#
|
|
578
|
+
# @return [void]
|
|
501
579
|
# @api private
|
|
502
580
|
def check_box_outdated
|
|
503
581
|
# Skip if box_auto_update is enabled (they'll get the update anyway)
|
|
@@ -519,6 +597,7 @@ module Kitchen
|
|
|
519
597
|
# Parse vagrant box outdated output and warn if a new version is available
|
|
520
598
|
#
|
|
521
599
|
# @param output [String] output from vagrant box outdated command
|
|
600
|
+
# @return [void]
|
|
522
601
|
# @api private
|
|
523
602
|
def warn_if_outdated(output)
|
|
524
603
|
return unless box_is_outdated?(output)
|
|
@@ -549,15 +628,20 @@ module Kitchen
|
|
|
549
628
|
output_downcase.include?("newer version of the box")
|
|
550
629
|
end
|
|
551
630
|
|
|
631
|
+
# Characters that may legitimately appear inside a box version. Vagrant
|
|
632
|
+
# quotes versions in prose ("version '202401.31.0'.") and separates them
|
|
633
|
+
# with punctuation in tabular output ("Current: 1.2.3, Latest: 4.5.6"),
|
|
634
|
+
# so the version has to end on an alphanumeric to avoid swallowing the
|
|
635
|
+
# trailing quote, comma or full stop.
|
|
636
|
+
VERSION_PATTERN = /v?(\w[\w.+-]*\w|\w)/
|
|
637
|
+
|
|
552
638
|
# Extract current version from vagrant box outdated output
|
|
553
639
|
#
|
|
554
640
|
# @param output [String] output from vagrant box outdated command
|
|
555
641
|
# @return [String, nil] current version or nil if not found
|
|
556
642
|
# @api private
|
|
557
643
|
def extract_current_version(output)
|
|
558
|
-
|
|
559
|
-
output.match(/currently have version\s+'?v?([^'.\s]+)/i)
|
|
560
|
-
match ? match[1] : nil
|
|
644
|
+
extract_version(output, /Current:\s+/i, /currently have version\s+'?/i)
|
|
561
645
|
end
|
|
562
646
|
|
|
563
647
|
# Extract latest version from vagrant box outdated output
|
|
@@ -566,12 +650,32 @@ module Kitchen
|
|
|
566
650
|
# @return [String, nil] latest version or nil if not found
|
|
567
651
|
# @api private
|
|
568
652
|
def extract_latest_version(output)
|
|
569
|
-
|
|
570
|
-
output.match(/latest is version\s+'?v?([^'.\s]+)/i)
|
|
571
|
-
match ? match[1] : nil
|
|
653
|
+
extract_version(output, /Latest:\s+/i, /latest is version\s+'?/i)
|
|
572
654
|
end
|
|
573
655
|
|
|
574
|
-
#
|
|
656
|
+
# Finds the first version number that follows any of the given prefixes.
|
|
657
|
+
#
|
|
658
|
+
# @param output [String] output from vagrant box outdated command
|
|
659
|
+
# @param prefixes [Array<Regexp>] prefixes to look for, in priority order
|
|
660
|
+
# @return [String, nil] the version, or nil if no prefix matched
|
|
661
|
+
# @api private
|
|
662
|
+
def extract_version(output, *prefixes)
|
|
663
|
+
prefixes.each do |prefix|
|
|
664
|
+
match = output.match(/#{prefix.source}#{VERSION_PATTERN.source}/i)
|
|
665
|
+
return match[1] if match
|
|
666
|
+
end
|
|
667
|
+
nil
|
|
668
|
+
end
|
|
669
|
+
|
|
670
|
+
# Runs the `vagrant box update` command built by
|
|
671
|
+
# {#finalize_box_auto_update!}, if any.
|
|
672
|
+
#
|
|
673
|
+
# A box that has never been downloaded cannot be updated; that specific
|
|
674
|
+
# failure is expected on a first run and is swallowed.
|
|
675
|
+
#
|
|
676
|
+
# @return [void]
|
|
677
|
+
# @raise [Kitchen::ShellOut::ShellCommandFailed] for any other failure
|
|
678
|
+
# @api private
|
|
575
679
|
def run_box_auto_update
|
|
576
680
|
if config[:box_auto_update]
|
|
577
681
|
begin
|
|
@@ -584,15 +688,21 @@ module Kitchen
|
|
|
584
688
|
end
|
|
585
689
|
end
|
|
586
690
|
|
|
587
|
-
#
|
|
691
|
+
# Runs the `vagrant box prune` command built by
|
|
692
|
+
# {#finalize_box_auto_prune!}, if any.
|
|
693
|
+
#
|
|
694
|
+
# @return [void]
|
|
695
|
+
# @api private
|
|
588
696
|
def run_box_auto_prune
|
|
589
697
|
if config[:box_auto_prune]
|
|
590
698
|
run(config[:box_auto_prune])
|
|
591
699
|
end
|
|
592
700
|
end
|
|
593
701
|
|
|
594
|
-
# Runs
|
|
702
|
+
# Runs `:pre_create_command`, if set, from the kitchen root -- before
|
|
703
|
+
# `vagrant up`, so it can prepare anything the Vagrantfile depends on.
|
|
595
704
|
#
|
|
705
|
+
# @return [void]
|
|
596
706
|
# @api private
|
|
597
707
|
def run_pre_create_command
|
|
598
708
|
if config[:pre_create_command]
|
|
@@ -603,6 +713,8 @@ module Kitchen
|
|
|
603
713
|
# Runs a local command without streaming the stdout to the logger.
|
|
604
714
|
#
|
|
605
715
|
# @param cmd [String] command to run locally
|
|
716
|
+
# @param options [Hash] options hash
|
|
717
|
+
# @return [String] the standard output of the command
|
|
606
718
|
# @api private
|
|
607
719
|
def run_silently(cmd, options = {})
|
|
608
720
|
merged = {
|
|
@@ -613,6 +725,7 @@ module Kitchen
|
|
|
613
725
|
|
|
614
726
|
# Runs the `vagrant up` command locally.
|
|
615
727
|
#
|
|
728
|
+
# @return [void]
|
|
616
729
|
# @api private
|
|
617
730
|
def run_vagrant_up
|
|
618
731
|
cmd = "#{config[:vagrant_binary]} up"
|
|
@@ -621,9 +734,11 @@ module Kitchen
|
|
|
621
734
|
run(cmd)
|
|
622
735
|
end
|
|
623
736
|
|
|
624
|
-
#
|
|
737
|
+
# Records the connection details Vagrant reports for the new machine
|
|
738
|
+
# into the instance state, so the transport can reach it.
|
|
625
739
|
#
|
|
626
740
|
# @param state [Hash] mutable instance state
|
|
741
|
+
# @return [void]
|
|
627
742
|
# @api private
|
|
628
743
|
def update_state(state)
|
|
629
744
|
hash = winrm_transport? ? vagrant_config(:winrm) : vagrant_config(:ssh)
|
data/templates/Vagrantfile.erb
CHANGED
|
@@ -85,7 +85,7 @@ Vagrant.configure("2") do |c|
|
|
|
85
85
|
<% end %>
|
|
86
86
|
|
|
87
87
|
<% Array(config[:network]).each do |opts| %>
|
|
88
|
-
c.vm.network(:<%= opts[0] %>, <%= opts[1]
|
|
88
|
+
c.vm.network(:<%= opts[0] %>, <%= format_network_options(opts[1]) %>)
|
|
89
89
|
<% end %>
|
|
90
90
|
|
|
91
91
|
c.vm.synced_folder ".", "/vagrant", disabled: true
|
|
@@ -97,6 +97,8 @@ Vagrant.configure("2") do |c|
|
|
|
97
97
|
<% case config[:provider]
|
|
98
98
|
when "virtualbox" %>
|
|
99
99
|
p.name = "kitchen-<%= File.basename(config[:kitchen_root]) %>-<%= instance.name %>-<%= SecureRandom.uuid %>"
|
|
100
|
+
<% when "tart" %>
|
|
101
|
+
p.name = "kitchen-<%= File.basename(config[:kitchen_root]) %>-<%= instance.name %>"
|
|
100
102
|
<% end %>
|
|
101
103
|
|
|
102
104
|
<% case config[:provider]
|
metadata
CHANGED
|
@@ -1,15 +1,29 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: kitchen-vagrant
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Fletcher Nichol
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-08-22 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: base64
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '0.2'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '0.2'
|
|
13
27
|
- !ruby/object:Gem::Dependency
|
|
14
28
|
name: test-kitchen
|
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -55,7 +69,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
55
69
|
requirements:
|
|
56
70
|
- - ">="
|
|
57
71
|
- !ruby/object:Gem::Version
|
|
58
|
-
version: '3.
|
|
72
|
+
version: '3.1'
|
|
59
73
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
60
74
|
requirements:
|
|
61
75
|
- - ">="
|