kitchen-vagrant 2.3.0 → 2.4.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: cf0fbd431e7e5a52a144f6ce2e79edea1d2783c74c0ef212c3674a12e147683e
4
- data.tar.gz: fdde8621c74520cf97a5367bfa3098aedc814d8037ad564ef8cada2056237807
3
+ metadata.gz: 6ded9303b651d9e3d46c4d56a805da70902c941946e6f034635e3ccedef10e37
4
+ data.tar.gz: 721a9bdf7801068039a3e4a446f92866e90601fc86f35cf4e4d6a284b62fb95b
5
5
  SHA512:
6
- metadata.gz: 1877e0240f40b4d4880ba3032f9801a984252051a88ba2a8fc0bd5af9d314ac5aa701b1116e9df747614b6ca3adacbbf898be6fdfe1d3d104f41f2321d2aceaa
7
- data.tar.gz: eef20bc7471c539f0b11cbb31d80337bf7037905e7a1fecc9f7104d9b9335f57bd5d5437e376bb19942d5e80dcffb5193ba5ddab7836d8c3cb315aced9149361
6
+ metadata.gz: 67975ca9f88c44ab626a92acdd66ea6fe077da509ac856c76c1b40f0f36391a33d3d9b55332bd8ad84ccce722ad550460f7072338ef7ae27d240cccc3d920827
7
+ data.tar.gz: 856a7d25b3a15cb4792f07f69b1b20b4c957bf5eaa062f1cfa05a9fe32bd810522072eb46ee88915ebbe4149851b387e8e2b8708df9b66c796daaa7b7c00479c
@@ -127,7 +127,7 @@ module Kitchen
127
127
  # @param cmd [String] command to run locally
128
128
  # @param options [Hash] options hash
129
129
  # @return [Hash,nil] the parsed JSON the script emitted, if any
130
- # @see Kitchen::ShellOut.run_command
130
+ # @see Kitchen::ShellOut#run_command
131
131
  # @api private
132
132
  def run_ps(cmd, options = {})
133
133
  cmd = "echo #{cmd}" if config[:dry_run]
@@ -18,6 +18,9 @@
18
18
  require "erb" unless defined?(Erb)
19
19
  require "fileutils" unless defined?(FileUtils)
20
20
  require "rubygems/version"
21
+ # Chefstyle's Chef/Ruby/UnlessDefinedRequire wants this guard, even though the
22
+ # guard's other branch is unreachable: kitchen has already loaded "time" by here.
23
+ require "time" unless defined?(Time.now.iso8601)
21
24
 
22
25
  require "kitchen"
23
26
  require_relative "vagrant_version"
@@ -31,6 +34,10 @@ module Kitchen
31
34
  #
32
35
  # @author Fletcher Nichol <fnichol@nichol.ca>
33
36
  class Vagrant < Kitchen::Driver::Base
37
+ # Machine states Vagrant reports for a box that is up and reachable.
38
+ #
39
+ # @return [Array<String>]
40
+ LIVE_STATES = %w{running}.freeze
34
41
 
35
42
  include ShellOut
36
43
  include Kitchen::Driver::HypervHelpers
@@ -101,11 +108,17 @@ module Kitchen
101
108
  driver.windows_os? ? "/omnibus/cache" : "/tmp/omnibus/cache"
102
109
  end
103
110
 
104
- # for use with vagrant on WSL
105
- user_home = ENV["VAGRANT_WSL_WINDOWS_ACCESS_USER_HOME_PATH"].nil? ? "~" : ENV["VAGRANT_WSL_WINDOWS_ACCESS_USER_HOME_PATH"]
106
-
107
- default_config :kitchen_cache_directory,
111
+ # Resolved per instance rather than when this file is loaded, so that
112
+ # `VAGRANT_WSL_WINDOWS_ACCESS_USER_HOME_PATH` is read at the moment the
113
+ # driver needs it -- the same way `:provider` reads
114
+ # `VAGRANT_DEFAULT_PROVIDER`. Reading it eagerly froze one value into the
115
+ # class for the life of the process, which is wrong for anything that
116
+ # sets the variable after the driver has been required, and made the
117
+ # setting impossible to exercise.
118
+ default_config(:kitchen_cache_directory) do |_|
119
+ user_home = ENV["VAGRANT_WSL_WINDOWS_ACCESS_USER_HOME_PATH"] || "~"
108
120
  File.expand_path("#{user_home}/.kitchen/cache")
121
+ end
109
122
 
110
123
  default_config :cachier, nil
111
124
 
@@ -114,6 +127,7 @@ module Kitchen
114
127
  # Creates a Vagrant VM instance.
115
128
  #
116
129
  # @param state [Hash] mutable instance state
130
+ # @return [void]
117
131
  # @raise [ActionFailed] if the action could not be completed
118
132
  def create(state)
119
133
  create_vagrantfile
@@ -154,6 +168,7 @@ module Kitchen
154
168
  # Destroys an instance.
155
169
  #
156
170
  # @param state [Hash] mutable instance state
171
+ # @return [void]
157
172
  # @raise [ActionFailed] if the action could not be completed
158
173
  def destroy(state)
159
174
  return if state[:hostname].nil?
@@ -171,6 +186,7 @@ module Kitchen
171
186
  # current working directory, then destroys the instance.
172
187
  #
173
188
  # @param state [Hash] mutable instance state
189
+ # @return [void]
174
190
  # @raise [UserError] if the instance has not been created
175
191
  # @raise [ActionFailed] if the action could not be completed
176
192
  def package(state)
@@ -188,6 +204,27 @@ module Kitchen
188
204
  destroy(state)
189
205
  end
190
206
 
207
+ # Reports what Vagrant currently thinks of the machine.
208
+ #
209
+ # @param state [Hash] instance state naming the machine
210
+ # @return [Hash] a Test Kitchen status hash, or the base implementation's
211
+ # answer when there is nothing to ask Vagrant about
212
+ def status(state)
213
+ return super unless state[:hostname]
214
+
215
+ machine_state = vagrant_machine_state
216
+ return super unless machine_state
217
+
218
+ {
219
+ live: LIVE_STATES.include?(machine_state),
220
+ state: machine_state,
221
+ source: "driver",
222
+ resource_id: instance.name,
223
+ message: "Vagrant reports the machine as #{machine_state}",
224
+ checked_at: Time.now.utc.iso8601,
225
+ }
226
+ end
227
+
191
228
  # A lifecycle method that should be invoked when the object is about
192
229
  # ready to be used. A reference to an Instance is required as
193
230
  # configuration dependant data may be access through an Instance. This
@@ -214,6 +251,7 @@ module Kitchen
214
251
  # checking for the presence of certain directories, software installed,
215
252
  # etc.
216
253
  #
254
+ # @return [void]
217
255
  # @raise [UserError] if the driver will not be able to perform or if a
218
256
  # documented dependency is missing from the system
219
257
  def verify_dependencies
@@ -225,6 +263,23 @@ module Kitchen
225
263
  end
226
264
  end
227
265
 
266
+ # Checks the host-side things a Vagrant run needs, reporting rather than
267
+ # raising so `kitchen doctor` can list every problem at once.
268
+ #
269
+ # {#verify_dependencies} already raises on an old or absent Vagrant, but
270
+ # it only runs on the actions that need it. This repeats the version rule
271
+ # as a report and adds the file and folder checks that nothing validates
272
+ # today.
273
+ #
274
+ # @param state [Hash] mutable instance and driver state
275
+ # @return [Boolean] true when a problem was reported
276
+ def doctor(state) # rubocop:disable Lint/UnusedMethodArgument
277
+ problems = vagrant_problems + template_problems + synced_folder_problems
278
+
279
+ problems.each { |problem| warn(problem) }
280
+ !problems.empty?
281
+ end
282
+
228
283
  # @return [TrueClass,FalseClass] whether or not the transport's name
229
284
  # implies a WinRM-based transport
230
285
  # @api private
@@ -254,9 +309,20 @@ module Kitchen
254
309
  MIN_VER = "2.4.0".freeze
255
310
 
256
311
  class << self
257
- # @return [String] the version of Vagrant installed on the workstation
312
+ # Memoises `vagrant --version` for the life of the process, so that
313
+ # every instance in a multi-instance run shells out at most once.
314
+ #
315
+ # @return [String,nil] the version of Vagrant installed on the
316
+ # workstation, or nil before anything has looked it up
258
317
  # @api private
259
318
  attr_accessor :vagrant_version
319
+
320
+ # @!method self.vagrant_version=(value)
321
+ # Records the version of Vagrant found on the workstation.
322
+ #
323
+ # @param value [String] the version string to memoise
324
+ # @return [String] the version string just stored
325
+ # @api private
260
326
  end
261
327
 
262
328
  # Returns whether or not a platform name could have a corresponding Bento
@@ -376,6 +442,7 @@ module Kitchen
376
442
 
377
443
  # Replaces any `{{vagrant_root}}` tokens in the pre create command.
378
444
  #
445
+ # @return [void]
379
446
  # @api private
380
447
  def finalize_pre_create_command!
381
448
  return if config[:pre_create_command].nil?
@@ -503,11 +570,98 @@ module Kitchen
503
570
  end
504
571
  end
505
572
 
506
- # Convenience method to run a command locally.
573
+ # Asks Vagrant for the machine state.
574
+ #
575
+ # `--machine-readable` is parsed rather than the human output because the
576
+ # human wording is localised and reworded between Vagrant releases, while
577
+ # the machine format is a stable comma-separated
578
+ # `timestamp,target,type,data` and the `state` row carries the raw value
579
+ # (`running`, `poweroff`, `not_created`, ...).
580
+ #
581
+ # @return [String, nil] the machine state, or nil when there is no
582
+ # Vagrantfile to ask about, the command fails, or no state row is found
583
+ # @api private
584
+ def vagrant_machine_state
585
+ return nil unless File.exist?(File.join(vagrant_root, "Vagrantfile"))
586
+
587
+ output = run("#{config[:vagrant_binary]} status --machine-readable")
588
+ parse_machine_state(output)
589
+ rescue ::StandardError => e
590
+ debug("Could not read the Vagrant machine state: #{e.message}")
591
+ nil
592
+ end
593
+
594
+ # Pulls the `state` row out of Vagrant's machine-readable output.
595
+ #
596
+ # @param output [String] the raw `--machine-readable` output
597
+ # @return [String, nil] the state value, or nil when no state row is present
598
+ # @api private
599
+ def parse_machine_state(output)
600
+ output.to_s.each_line do |line|
601
+ fields = line.strip.split(",")
602
+ return fields[3] if fields[2] == "state" && fields[3]
603
+ end
604
+ nil
605
+ end
606
+
607
+ # Vagrant itself: present, and new enough.
608
+ #
609
+ # @return [Array<String>] a problem, or an empty array
610
+ def vagrant_problems
611
+ found = vagrant_version
612
+ if Gem::Version.new(found) < Gem::Version.new(MIN_VER.dup)
613
+ return ["Vagrant #{found} is older than the #{MIN_VER} this driver " \
614
+ "needs. Upgrade from #{WEBSITE}."]
615
+ end
616
+
617
+ info("vagrant #{found} found at #{config[:vagrant_binary]}")
618
+ []
619
+ rescue UserError => e
620
+ [e.message]
621
+ rescue ::StandardError => e
622
+ ["Could not run #{config[:vagrant_binary]} --version: #{e.message}"]
623
+ end
624
+
625
+ # The Vagrantfile template, and any extra Vagrantfiles spliced into it.
626
+ # Both are `expand_path_for` settings, so a wrong relative path becomes
627
+ # an absolute path that simply is not there.
628
+ #
629
+ # @return [Array<String>] one problem per missing file
630
+ def template_problems
631
+ problems = []
632
+
633
+ unless File.exist?(config[:vagrantfile_erb].to_s)
634
+ problems << "vagrantfile_erb #{config[:vagrantfile_erb]} does not exist."
635
+ end
636
+
637
+ Array(config[:vagrantfiles]).each do |path|
638
+ problems << "vagrantfiles entry #{path} does not exist." unless File.exist?(path.to_s)
639
+ end
640
+
641
+ problems
642
+ end
643
+
644
+ # Host paths in `synced_folders`. Vagrant creates a missing host path
645
+ # silently for some providers and fails for others, so an absent source
646
+ # is worth naming either way.
647
+ #
648
+ # @return [Array<String>] one problem per missing host path
649
+ def synced_folder_problems
650
+ Array(config[:synced_folders]).filter_map do |source, destination, _options|
651
+ next if source.nil? || File.exist?(source.to_s)
652
+
653
+ "synced_folders source #{source} (mounted at #{destination}) does not exist."
654
+ end
655
+ end
656
+
657
+ # Convenience method to run a command locally, from {#vagrant_root}.
507
658
  #
508
659
  # @param cmd [String] command to run locally
509
660
  # @param options [Hash] options hash
510
- # @see Kitchen::ShellOut.run_command
661
+ # @return [String] the standard output of the command
662
+ # @raise [Kitchen::ShellOut::ShellCommandFailed] if the command exits
663
+ # non-zero
664
+ # @see Kitchen::ShellOut#run_command
511
665
  # @api private
512
666
  def run(cmd, options = {})
513
667
  cmd = "echo #{cmd}" if config[:dry_run]
@@ -529,6 +683,8 @@ module Kitchen
529
683
  # @param cmd [String] command to run locally
530
684
  # @param options [Hash] options hash
531
685
  # @return [String] the standard output of the command
686
+ # @raise [Kitchen::ShellOut::ShellCommandFailed] if the command exits
687
+ # non-zero
532
688
  # @see Kitchen::ShellOut#run_command
533
689
  # rubocop:disable Metrics/CyclomaticComplexity
534
690
  def run_command(cmd, options = {})
@@ -752,7 +908,12 @@ module Kitchen
752
908
  state[:rdp_port] = hash["RDPPort"] if hash["RDPPort"]
753
909
  end
754
910
 
755
- # @return [String] full absolute path to the kitchen cache directory
911
+ # The *host* side of the omnibus package cache: the directory that
912
+ # {#add_extra_synced_folders!} shares into the guest, where it is
913
+ # mounted at {#cache_directory}.
914
+ #
915
+ # @return [String] full absolute path, on the host, to the kitchen
916
+ # cache directory
756
917
  # @api private
757
918
  def local_kitchen_cache
758
919
  @local_kitchen_cache ||= config[:kitchen_cache_directory]
@@ -789,9 +950,15 @@ module Kitchen
789
950
  false
790
951
  end
791
952
 
792
- # Converts a Windows path to a WSL path
793
- # @param path [String] Windows path (e.g., "C:/Users/...")
794
- # @return [String] WSL path (e.g., "/mnt/c/users/...")
953
+ # Converts a Windows path to a WSL path.
954
+ #
955
+ # Anything that does not look like a drive-lettered Windows path is
956
+ # returned untouched. Note that the conversion downcases the whole
957
+ # path, not just the drive letter, so a path whose remainder is
958
+ # case-sensitive does not survive it.
959
+ #
960
+ # @param path [String] Windows path (e.g., `"C:/Users/..."`)
961
+ # @return [String] WSL path (e.g., `"/mnt/c/users/..."`)
795
962
  # @api private
796
963
  def windows_to_wsl_path(path)
797
964
  # Only convert if it looks like a Windows path
@@ -21,6 +21,6 @@ module Kitchen
21
21
  module Driver
22
22
 
23
23
  # Version string for Vagrant Kitchen driver
24
- VAGRANT_VERSION = "2.3.0".freeze
24
+ VAGRANT_VERSION = "2.4.1".freeze
25
25
  end
26
26
  end
@@ -99,6 +99,8 @@ Vagrant.configure("2") do |c|
99
99
  p.name = "kitchen-<%= File.basename(config[:kitchen_root]) %>-<%= instance.name %>-<%= SecureRandom.uuid %>"
100
100
  <% when "tart" %>
101
101
  p.name = "kitchen-<%= File.basename(config[:kitchen_root]) %>-<%= instance.name %>"
102
+ <% when "libvirt" %>
103
+ p.default_prefix = "<%="kitchen-#{File.basename(config[:kitchen_root])}-#{instance.name}-#{SecureRandom.uuid}"[0..99].chomp("-") %>"
102
104
  <% end %>
103
105
 
104
106
  <% case config[:provider]
@@ -257,7 +259,9 @@ Vagrant.configure("2") do |c|
257
259
  end
258
260
 
259
261
  <% if config[:env] && !config[:env].empty? %>
260
- # Set environment variables
262
+ # Environment variables for the *guest*, not for the host's Vagrant
263
+ # process: each entry becomes an export line in /etc/profile.d/kitchen.sh,
264
+ # so it applies to logins on Linux guests only.
261
265
  <% config[:env].each do |env_var| %>
262
266
  c.vm.provision "shell", inline: <<-SHELL
263
267
  echo 'export <%= env_var.gsub("'", "'\\\\''") %>' >> /etc/profile.d/kitchen.sh
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kitchen-vagrant
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.0
4
+ version: 2.4.1
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-08-22 00:00:00.000000000 Z
11
+ date: 2026-08-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: base64
@@ -30,7 +30,7 @@ dependencies:
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '1.4'
33
+ version: '3.0'
34
34
  - - "<"
35
35
  - !ruby/object:Gem::Version
36
36
  version: '5'
@@ -40,7 +40,7 @@ dependencies:
40
40
  requirements:
41
41
  - - ">="
42
42
  - !ruby/object:Gem::Version
43
- version: '1.4'
43
+ version: '3.0'
44
44
  - - "<"
45
45
  - !ruby/object:Gem::Version
46
46
  version: '5'