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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4abf5224b64f63f370ce34d71838b1aa1706a70a2a8f7285219388a977eb2bdf
4
- data.tar.gz: 91b8de7ff382f07694a1df7d7714237e77be14be7b4faa854b509e97dc31fc31
3
+ metadata.gz: cf0fbd431e7e5a52a144f6ce2e79edea1d2783c74c0ef212c3674a12e147683e
4
+ data.tar.gz: fdde8621c74520cf97a5367bfa3098aedc814d8037ad564ef8cada2056237807
5
5
  SHA512:
6
- metadata.gz: 3b42b779d8c9726c89ef893e2ae4289775ae488eb26d2ff52d3a909e3efd97296db770801908a41beb73df703a9e065dae8836b82ce0fab7fc4dc9eb968ba02d
7
- data.tar.gz: 4656b6f370e4c2233ad1c0fb8ab933599829599348fab18461f8ab487df9e180b040267e3fcd01124453b7c223f84792e276b7f8140ecf4e8c03377d62e79eb7
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
- os_arch = ENV["PROCESSOR_ARCHITEW6432"] || ENV["PROCESSOR_ARCHITECTURE"]
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
- os_arch = ENV["PROCESSOR_ARCHITEW6432"] || ENV["PROCESSOR_ARCHITECTURE"]
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
- # Setting up the `cache_directory` to store omnibus packages in cache
220
- # and share a local folder to that directory so that we don't pull them
221
- # down every single time
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
- # Retuns whether or not a platform name could have a correcponding Bento
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
- # @return [TrueClass,FalseClass] whether or not the box shoud work with
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
- # Setup path for CA cert
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
- # Create vagrant command to update box to the latest version
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 if config[:box_auto_update].nil?
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
- # Create vagrant command to remove older versions of the box
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 if config[:box_auto_prune].nil?
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
- # Replaces an `%{instance_name}` tokens in the synced folder items.
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
- # We would like to sync a local folder to the instance so we can
379
- # take advantage of the packages that we might have in cache,
380
- # therefore we wont download a package we already have
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 the length of `:vm_hostname` to 12 characters for
393
- # Windows-based operating systems.
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
- # If Hyper-V and no network configuration
405
- # check KITCHEN_HYPERV_SWITCH and fallback to helper method
406
- # to select the best switch
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
- if config[:provider] == "hyperv" && config[:network].empty?
410
- config[:network].push([
411
- "public_network",
412
- "bridge: \"#{hyperv_switch}\"",
413
- ])
414
- end
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 efectively prepend the vagrant ruby path in a persistent
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 dispair
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 user
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
- match = output.match(/Current:\s+v?(\S+)/i) ||
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
- match = output.match(/Latest:\s+v?(\S+)/i) ||
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
- # Tell vagrant to update vagrant box to latest version
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
- # Tell vagrant to remove older vagrant boxes
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 a local command before `vagrant up` has been called.
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
- # Updates any state after creation.
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)
@@ -17,9 +17,10 @@
17
17
 
18
18
  module Kitchen
19
19
 
20
+ # Test Kitchen driver plugins.
20
21
  module Driver
21
22
 
22
23
  # Version string for Vagrant Kitchen driver
23
- VAGRANT_VERSION = "2.2.1".freeze
24
+ VAGRANT_VERSION = "2.3.0".freeze
24
25
  end
25
26
  end
@@ -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].map { |k, v| "#{k}: #{v.inspect}" }.join(', ') %>)
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.2.1
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-01-22 00:00:00.000000000 Z
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.0'
72
+ version: '3.1'
59
73
  required_rubygems_version: !ruby/object:Gem::Requirement
60
74
  requirements:
61
75
  - - ">="