kitchen-vagrant 2.2.0 → 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 +178 -42
- data/lib/kitchen/driver/vagrant_version.rb +2 -1
- data/templates/Vagrantfile.erb +13 -1
- metadata +19 -5
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
|
|
|
@@ -80,6 +80,8 @@ module Kitchen
|
|
|
80
80
|
|
|
81
81
|
default_config :synced_folders, []
|
|
82
82
|
|
|
83
|
+
default_config :env, []
|
|
84
|
+
|
|
83
85
|
default_config :use_cached_chef_client, false
|
|
84
86
|
|
|
85
87
|
default_config :vagrant_binary, "vagrant"
|
|
@@ -125,6 +127,11 @@ module Kitchen
|
|
|
125
127
|
info("Vagrant instance #{instance.to_str} created.")
|
|
126
128
|
end
|
|
127
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
|
+
#
|
|
128
135
|
# @return [String,nil] the Vagrant box for this Instance
|
|
129
136
|
def default_box
|
|
130
137
|
if bento_box?(instance.platform.name)
|
|
@@ -134,6 +141,11 @@ module Kitchen
|
|
|
134
141
|
end
|
|
135
142
|
end
|
|
136
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
|
+
#
|
|
137
149
|
# @return [String,nil] the Vagrant box URL for this Instance
|
|
138
150
|
def default_box_url
|
|
139
151
|
nil
|
|
@@ -155,6 +167,12 @@ module Kitchen
|
|
|
155
167
|
state.delete(:hostname)
|
|
156
168
|
end
|
|
157
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
|
|
158
176
|
def package(state)
|
|
159
177
|
if state[:hostname].nil?
|
|
160
178
|
raise UserError, "Vagrant instance not created!"
|
|
@@ -214,9 +232,11 @@ module Kitchen
|
|
|
214
232
|
instance.transport.name.downcase =~ /win_?rm/
|
|
215
233
|
end
|
|
216
234
|
|
|
217
|
-
#
|
|
218
|
-
#
|
|
219
|
-
#
|
|
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
|
|
220
240
|
def cache_directory
|
|
221
241
|
if enable_cache?
|
|
222
242
|
config[:cache_directory]
|
|
@@ -227,7 +247,10 @@ module Kitchen
|
|
|
227
247
|
|
|
228
248
|
protected
|
|
229
249
|
|
|
250
|
+
# Where users are pointed when Vagrant is missing or too old.
|
|
230
251
|
WEBSITE = "https://developer.hashicorp.com/vagrant/install".freeze
|
|
252
|
+
|
|
253
|
+
# The oldest Vagrant this driver supports.
|
|
231
254
|
MIN_VER = "2.4.0".freeze
|
|
232
255
|
|
|
233
256
|
class << self
|
|
@@ -236,10 +259,11 @@ module Kitchen
|
|
|
236
259
|
attr_accessor :vagrant_version
|
|
237
260
|
end
|
|
238
261
|
|
|
239
|
-
#
|
|
262
|
+
# Returns whether or not a platform name could have a corresponding Bento
|
|
240
263
|
# box produced by the Bento project.
|
|
241
264
|
# (https://github.com/chef/bento).
|
|
242
265
|
#
|
|
266
|
+
# @param name [String] a Test Kitchen platform name
|
|
243
267
|
# @return [TrueClass,FalseClass] whether or not the name could be a Bento
|
|
244
268
|
# box
|
|
245
269
|
# @api private
|
|
@@ -248,8 +272,13 @@ module Kitchen
|
|
|
248
272
|
end
|
|
249
273
|
|
|
250
274
|
# Returns whether or not the we expect the box to work with shared folders
|
|
251
|
-
# by matching against a whitelist of bento boxes
|
|
252
|
-
#
|
|
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
|
|
253
282
|
# shared folders
|
|
254
283
|
# @api private
|
|
255
284
|
def safe_share?(box)
|
|
@@ -259,7 +288,11 @@ module Kitchen
|
|
|
259
288
|
end
|
|
260
289
|
|
|
261
290
|
# Return true if we found the criteria to enable the cache_directory
|
|
262
|
-
# functionality
|
|
291
|
+
# functionality.
|
|
292
|
+
#
|
|
293
|
+
# @return [TrueClass,FalseClass] whether the package cache should be
|
|
294
|
+
# shared into the guest
|
|
295
|
+
# @api private
|
|
263
296
|
def enable_cache?
|
|
264
297
|
return false unless config[:cache_directory]
|
|
265
298
|
return true if safe_share?(config[:box])
|
|
@@ -269,8 +302,10 @@ module Kitchen
|
|
|
269
302
|
false
|
|
270
303
|
end
|
|
271
304
|
|
|
272
|
-
# 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.
|
|
273
307
|
#
|
|
308
|
+
# @return [void]
|
|
274
309
|
# @api private
|
|
275
310
|
def create_vagrantfile
|
|
276
311
|
return if @vagrantfile_created
|
|
@@ -286,6 +321,7 @@ module Kitchen
|
|
|
286
321
|
# Logs the Vagrantfile's contents to the debug log level.
|
|
287
322
|
#
|
|
288
323
|
# @param vagrantfile [String] path to the Vagrantfile
|
|
324
|
+
# @return [void]
|
|
289
325
|
# @api private
|
|
290
326
|
def debug_vagrantfile(vagrantfile)
|
|
291
327
|
return unless logger.debug?
|
|
@@ -295,8 +331,10 @@ module Kitchen
|
|
|
295
331
|
debug("------------")
|
|
296
332
|
end
|
|
297
333
|
|
|
298
|
-
#
|
|
334
|
+
# Expands `:box_download_ca_cert` relative to the kitchen root, so a
|
|
335
|
+
# `.kitchen.yml` can refer to a cert alongside itself.
|
|
299
336
|
#
|
|
337
|
+
# @return [void]
|
|
300
338
|
# @api private
|
|
301
339
|
def finalize_ca_cert!
|
|
302
340
|
unless config[:box_download_ca_cert].nil?
|
|
@@ -306,9 +344,14 @@ module Kitchen
|
|
|
306
344
|
end
|
|
307
345
|
end
|
|
308
346
|
|
|
309
|
-
#
|
|
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
|
|
310
353
|
def finalize_box_auto_update!
|
|
311
|
-
return
|
|
354
|
+
return unless config[:box_auto_update]
|
|
312
355
|
|
|
313
356
|
cmd = "#{config[:vagrant_binary]} box update --box #{config[:box]}"
|
|
314
357
|
cmd += " --architecture #{config[:box_arch]}" if config[:box_arch]
|
|
@@ -317,9 +360,14 @@ module Kitchen
|
|
|
317
360
|
config[:box_auto_update] = cmd
|
|
318
361
|
end
|
|
319
362
|
|
|
320
|
-
#
|
|
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
|
|
321
369
|
def finalize_box_auto_prune!
|
|
322
|
-
return
|
|
370
|
+
return unless config[:box_auto_prune]
|
|
323
371
|
|
|
324
372
|
cmd = "#{config[:vagrant_binary]} box prune --force --keep-active-boxes --name #{config[:box]}"
|
|
325
373
|
cmd += " --provider #{config[:provider]}" if config[:provider]
|
|
@@ -336,8 +384,45 @@ module Kitchen
|
|
|
336
384
|
.gsub("{{vagrant_root}}", vagrant_root)
|
|
337
385
|
end
|
|
338
386
|
|
|
339
|
-
#
|
|
387
|
+
# Formats synced folder options for use in the Vagrantfile.
|
|
388
|
+
# Accepts either a Hash (converts to Ruby hash syntax) or a String (returns as-is).
|
|
389
|
+
# Supports SMB options like smb_username, smb_password, etc.
|
|
390
|
+
#
|
|
391
|
+
# @param options [Hash, String, nil] synced folder options
|
|
392
|
+
# @return [String] formatted options string for Vagrantfile
|
|
393
|
+
# @api private
|
|
394
|
+
def format_synced_folder_options(options)
|
|
395
|
+
return "nil" if options.nil?
|
|
396
|
+
return options if options.is_a?(String)
|
|
397
|
+
|
|
398
|
+
# Convert Hash to Ruby hash literal syntax
|
|
399
|
+
if options.is_a?(Hash)
|
|
400
|
+
options.map { |k, v| "#{k}: #{v.inspect}" }.join(", ")
|
|
401
|
+
else
|
|
402
|
+
options.to_s
|
|
403
|
+
end
|
|
404
|
+
end
|
|
405
|
+
|
|
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.
|
|
340
424
|
#
|
|
425
|
+
# @return [void]
|
|
341
426
|
# @api private
|
|
342
427
|
def finalize_synced_folders!
|
|
343
428
|
config[:synced_folders] = config[:synced_folders]
|
|
@@ -348,15 +433,17 @@ module Kitchen
|
|
|
348
433
|
config[:kitchen_root]
|
|
349
434
|
),
|
|
350
435
|
destination.gsub("%{instance_name}", instance.name),
|
|
351
|
-
options
|
|
436
|
+
format_synced_folder_options(options),
|
|
352
437
|
]
|
|
353
438
|
end
|
|
354
439
|
add_extra_synced_folders!
|
|
355
440
|
end
|
|
356
441
|
|
|
357
|
-
#
|
|
358
|
-
#
|
|
359
|
-
#
|
|
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
|
|
360
447
|
def add_extra_synced_folders!
|
|
361
448
|
if cache_directory
|
|
362
449
|
FileUtils.mkdir_p(local_kitchen_cache)
|
|
@@ -368,9 +455,12 @@ module Kitchen
|
|
|
368
455
|
end
|
|
369
456
|
end
|
|
370
457
|
|
|
371
|
-
# Truncates
|
|
372
|
-
#
|
|
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.
|
|
373
462
|
#
|
|
463
|
+
# @return [void]
|
|
374
464
|
# @api private
|
|
375
465
|
def finalize_vm_hostname!
|
|
376
466
|
string = config[:vm_hostname]
|
|
@@ -380,17 +470,20 @@ module Kitchen
|
|
|
380
470
|
end
|
|
381
471
|
end
|
|
382
472
|
|
|
383
|
-
#
|
|
384
|
-
#
|
|
385
|
-
#
|
|
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]
|
|
386
479
|
# @api private
|
|
387
480
|
def finalize_network!
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
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}"}]]
|
|
394
487
|
end
|
|
395
488
|
|
|
396
489
|
# Renders the Vagrantfile ERb template.
|
|
@@ -433,6 +526,9 @@ module Kitchen
|
|
|
433
526
|
# any bundler environment should we detect one. Otherwise, subcommands
|
|
434
527
|
# will inherit our bundled environment.
|
|
435
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
|
|
436
532
|
# @see Kitchen::ShellOut#run_command
|
|
437
533
|
# rubocop:disable Metrics/CyclomaticComplexity
|
|
438
534
|
def run_command(cmd, options = {})
|
|
@@ -458,10 +554,10 @@ module Kitchen
|
|
|
458
554
|
# is passed to a windows process with a PATH, Vagrant's batch installer
|
|
459
555
|
# (https://github.com/mitchellh/vagrant-installers/blob/master/substrate
|
|
460
556
|
# /modules/vagrant_installer/templates/windows_vagrant.bat.erb)
|
|
461
|
-
# does not
|
|
557
|
+
# does not effectively prepend the vagrant ruby path in a persistent
|
|
462
558
|
# manner which causes vagrant to use the same ruby as test-kitchen and
|
|
463
559
|
# then the environment is essentially corrupted leading to many errors
|
|
464
|
-
# and
|
|
560
|
+
# and despair
|
|
465
561
|
unless windows_host?
|
|
466
562
|
gem_home = ENV["GEM_HOME"]
|
|
467
563
|
if gem_home && (env["PATH"] || ENV["PATH"])
|
|
@@ -475,8 +571,11 @@ module Kitchen
|
|
|
475
571
|
end
|
|
476
572
|
# rubocop:enable Metrics/CyclomaticComplexity
|
|
477
573
|
|
|
478
|
-
# 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.
|
|
479
577
|
#
|
|
578
|
+
# @return [void]
|
|
480
579
|
# @api private
|
|
481
580
|
def check_box_outdated
|
|
482
581
|
# Skip if box_auto_update is enabled (they'll get the update anyway)
|
|
@@ -498,6 +597,7 @@ module Kitchen
|
|
|
498
597
|
# Parse vagrant box outdated output and warn if a new version is available
|
|
499
598
|
#
|
|
500
599
|
# @param output [String] output from vagrant box outdated command
|
|
600
|
+
# @return [void]
|
|
501
601
|
# @api private
|
|
502
602
|
def warn_if_outdated(output)
|
|
503
603
|
return unless box_is_outdated?(output)
|
|
@@ -528,15 +628,20 @@ module Kitchen
|
|
|
528
628
|
output_downcase.include?("newer version of the box")
|
|
529
629
|
end
|
|
530
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
|
+
|
|
531
638
|
# Extract current version from vagrant box outdated output
|
|
532
639
|
#
|
|
533
640
|
# @param output [String] output from vagrant box outdated command
|
|
534
641
|
# @return [String, nil] current version or nil if not found
|
|
535
642
|
# @api private
|
|
536
643
|
def extract_current_version(output)
|
|
537
|
-
|
|
538
|
-
output.match(/currently have version\s+'?v?([^'.\s]+)/i)
|
|
539
|
-
match ? match[1] : nil
|
|
644
|
+
extract_version(output, /Current:\s+/i, /currently have version\s+'?/i)
|
|
540
645
|
end
|
|
541
646
|
|
|
542
647
|
# Extract latest version from vagrant box outdated output
|
|
@@ -545,12 +650,32 @@ module Kitchen
|
|
|
545
650
|
# @return [String, nil] latest version or nil if not found
|
|
546
651
|
# @api private
|
|
547
652
|
def extract_latest_version(output)
|
|
548
|
-
|
|
549
|
-
output.match(/latest is version\s+'?v?([^'.\s]+)/i)
|
|
550
|
-
match ? match[1] : nil
|
|
653
|
+
extract_version(output, /Latest:\s+/i, /latest is version\s+'?/i)
|
|
551
654
|
end
|
|
552
655
|
|
|
553
|
-
#
|
|
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
|
|
554
679
|
def run_box_auto_update
|
|
555
680
|
if config[:box_auto_update]
|
|
556
681
|
begin
|
|
@@ -563,15 +688,21 @@ module Kitchen
|
|
|
563
688
|
end
|
|
564
689
|
end
|
|
565
690
|
|
|
566
|
-
#
|
|
691
|
+
# Runs the `vagrant box prune` command built by
|
|
692
|
+
# {#finalize_box_auto_prune!}, if any.
|
|
693
|
+
#
|
|
694
|
+
# @return [void]
|
|
695
|
+
# @api private
|
|
567
696
|
def run_box_auto_prune
|
|
568
697
|
if config[:box_auto_prune]
|
|
569
698
|
run(config[:box_auto_prune])
|
|
570
699
|
end
|
|
571
700
|
end
|
|
572
701
|
|
|
573
|
-
# 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.
|
|
574
704
|
#
|
|
705
|
+
# @return [void]
|
|
575
706
|
# @api private
|
|
576
707
|
def run_pre_create_command
|
|
577
708
|
if config[:pre_create_command]
|
|
@@ -582,6 +713,8 @@ module Kitchen
|
|
|
582
713
|
# Runs a local command without streaming the stdout to the logger.
|
|
583
714
|
#
|
|
584
715
|
# @param cmd [String] command to run locally
|
|
716
|
+
# @param options [Hash] options hash
|
|
717
|
+
# @return [String] the standard output of the command
|
|
585
718
|
# @api private
|
|
586
719
|
def run_silently(cmd, options = {})
|
|
587
720
|
merged = {
|
|
@@ -592,6 +725,7 @@ module Kitchen
|
|
|
592
725
|
|
|
593
726
|
# Runs the `vagrant up` command locally.
|
|
594
727
|
#
|
|
728
|
+
# @return [void]
|
|
595
729
|
# @api private
|
|
596
730
|
def run_vagrant_up
|
|
597
731
|
cmd = "#{config[:vagrant_binary]} up"
|
|
@@ -600,9 +734,11 @@ module Kitchen
|
|
|
600
734
|
run(cmd)
|
|
601
735
|
end
|
|
602
736
|
|
|
603
|
-
#
|
|
737
|
+
# Records the connection details Vagrant reports for the new machine
|
|
738
|
+
# into the instance state, so the transport can reach it.
|
|
604
739
|
#
|
|
605
740
|
# @param state [Hash] mutable instance state
|
|
741
|
+
# @return [void]
|
|
606
742
|
# @api private
|
|
607
743
|
def update_state(state)
|
|
608
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]
|
|
@@ -253,4 +255,14 @@ Vagrant.configure("2") do |c|
|
|
|
253
255
|
<% end %>
|
|
254
256
|
<% end %>
|
|
255
257
|
end
|
|
258
|
+
|
|
259
|
+
<% if config[:env] && !config[:env].empty? %>
|
|
260
|
+
# Set environment variables
|
|
261
|
+
<% config[:env].each do |env_var| %>
|
|
262
|
+
c.vm.provision "shell", inline: <<-SHELL
|
|
263
|
+
echo 'export <%= env_var.gsub("'", "'\\\\''") %>' >> /etc/profile.d/kitchen.sh
|
|
264
|
+
SHELL
|
|
265
|
+
<% end %>
|
|
266
|
+
c.vm.provision "shell", inline: "chmod +x /etc/profile.d/kitchen.sh", run: "once"
|
|
267
|
+
<% end %>
|
|
256
268
|
end
|
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:
|
|
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
|
|
@@ -19,7 +33,7 @@ dependencies:
|
|
|
19
33
|
version: '1.4'
|
|
20
34
|
- - "<"
|
|
21
35
|
- !ruby/object:Gem::Version
|
|
22
|
-
version: '
|
|
36
|
+
version: '5'
|
|
23
37
|
type: :runtime
|
|
24
38
|
prerelease: false
|
|
25
39
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -29,7 +43,7 @@ dependencies:
|
|
|
29
43
|
version: '1.4'
|
|
30
44
|
- - "<"
|
|
31
45
|
- !ruby/object:Gem::Version
|
|
32
|
-
version: '
|
|
46
|
+
version: '5'
|
|
33
47
|
description: Kitchen::Driver::Vagrant - A HashiCorp Vagrant Driver for Test Kitchen.
|
|
34
48
|
email:
|
|
35
49
|
- fnichol@nichol.ca
|
|
@@ -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
|
- - ">="
|