test-kitchen 3.1.0 → 3.6.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/Gemfile +15 -10
- data/lib/kitchen/cli.rb +1 -1
- data/lib/kitchen/command/diagnose.rb +1 -1
- data/lib/kitchen/config.rb +8 -8
- data/lib/kitchen/configurable.rb +1 -1
- data/lib/kitchen/driver/ssh_base.rb +2 -2
- data/lib/kitchen/errors.rb +13 -0
- data/lib/kitchen/lifecycle_hook/base.rb +6 -4
- data/lib/kitchen/lifecycle_hook/local.rb +1 -1
- data/lib/kitchen/lifecycle_hooks.rb +3 -1
- data/lib/kitchen/loader/yaml.rb +1 -8
- data/lib/kitchen/platform.rb +1 -1
- data/lib/kitchen/platform_filter.rb +72 -0
- data/lib/kitchen/plugin_base.rb +0 -1
- data/lib/kitchen/provisioner/base.rb +7 -1
- data/lib/kitchen/provisioner/chef/common_sandbox.rb +8 -6
- data/lib/kitchen/provisioner/chef/policyfile.rb +11 -7
- data/lib/kitchen/provisioner/chef_base.rb +36 -19
- data/lib/kitchen/provisioner/shell.rb +0 -1
- data/lib/kitchen/ssh.rb +10 -3
- data/lib/kitchen/suite.rb +4 -2
- data/lib/kitchen/transport/base.rb +10 -6
- data/lib/kitchen/transport/ssh.rb +24 -11
- data/lib/kitchen/transport/winrm.rb +33 -9
- data/lib/kitchen/util.rb +13 -0
- data/lib/kitchen/verifier/base.rb +16 -7
- data/lib/kitchen/version.rb +1 -1
- data/lib/kitchen.rb +1 -1
- data/templates/driver/README.md.erb +2 -2
- data/test-kitchen.gemspec +7 -19
- metadata +63 -220
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ecd483d58546fb48da8bb5a4e5c448b7cc2f8b7d2c0082d0df4b023c380a2594
|
|
4
|
+
data.tar.gz: cb42f2dae4d33d84ff8515a7412d7e1d14c358504f66429b21465bef7714e48b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8adf00afe37d4b31dec9b6acca4aee2aa858b265db0fee4f0c0fac8407691f452e7d487d45ec5f72e816d0799060affcaf31d8885597ade1a9d40dc59f6056bc
|
|
7
|
+
data.tar.gz: bc82343bf133cbce4c9c5096d1d88a9bb7ab56cf619d289f71008388757d553c43432f3188d72ddc87c917212ce6a6278ee0d81a64b8f7d688341e387da2949f
|
data/Gemfile
CHANGED
|
@@ -1,21 +1,26 @@
|
|
|
1
1
|
source "https://rubygems.org"
|
|
2
2
|
|
|
3
|
-
# Specify your gem"s dependencies in test-kitchen.gemspec
|
|
4
3
|
gemspec
|
|
5
4
|
|
|
5
|
+
group :test do
|
|
6
|
+
gem "rake"
|
|
7
|
+
gem "rb-readline"
|
|
8
|
+
gem "aruba", ">= 0.11", "< 3.0"
|
|
9
|
+
gem "countloc", "~> 0.4"
|
|
10
|
+
gem "cucumber", ">= 2.1", "< 8.1"
|
|
11
|
+
gem "fakefs", "~> 2.0"
|
|
12
|
+
gem "maruku", "~> 0.6"
|
|
13
|
+
gem "minitest", "~> 5.3", "< 5.16"
|
|
14
|
+
gem "mocha", "~> 2.0"
|
|
15
|
+
end
|
|
16
|
+
|
|
6
17
|
group :integration do
|
|
7
18
|
gem "berkshelf"
|
|
8
|
-
gem "kitchen-inspec"
|
|
9
19
|
gem "kitchen-dokken"
|
|
20
|
+
gem "kitchen-inspec"
|
|
10
21
|
gem "kitchen-vagrant"
|
|
11
22
|
end
|
|
12
23
|
|
|
13
|
-
group :debug do
|
|
14
|
-
gem "pry", "~>0.12"
|
|
15
|
-
gem "pry-byebug"
|
|
16
|
-
gem "pry-stack_explorer"
|
|
17
|
-
end
|
|
18
|
-
|
|
19
24
|
group :chefstyle do
|
|
20
|
-
gem "chefstyle", "2.
|
|
21
|
-
end
|
|
25
|
+
gem "chefstyle", "2.2.3"
|
|
26
|
+
end
|
data/lib/kitchen/cli.rb
CHANGED
data/lib/kitchen/config.rb
CHANGED
|
@@ -216,11 +216,11 @@ module Kitchen
|
|
|
216
216
|
/^win/i.match?(platform) ? "winrm" : Transport::DEFAULT_PLUGIN
|
|
217
217
|
end,
|
|
218
218
|
},
|
|
219
|
-
kitchen_root
|
|
220
|
-
test_base_path
|
|
221
|
-
log_level
|
|
222
|
-
log_overwrite
|
|
223
|
-
debug
|
|
219
|
+
kitchen_root:,
|
|
220
|
+
test_base_path:,
|
|
221
|
+
log_level:,
|
|
222
|
+
log_overwrite:,
|
|
223
|
+
debug:,
|
|
224
224
|
}
|
|
225
225
|
end
|
|
226
226
|
|
|
@@ -250,8 +250,8 @@ module Kitchen
|
|
|
250
250
|
driver: new_driver(suite, platform),
|
|
251
251
|
lifecycle_hooks: new_lifecycle_hooks(suite, platform, sf),
|
|
252
252
|
logger: new_instance_logger(suite, platform, index),
|
|
253
|
-
suite
|
|
254
|
-
platform
|
|
253
|
+
suite:,
|
|
254
|
+
platform:,
|
|
255
255
|
provisioner: new_provisioner(suite, platform),
|
|
256
256
|
transport: new_transport(suite, platform),
|
|
257
257
|
verifier: new_verifier(suite, platform),
|
|
@@ -275,7 +275,7 @@ module Kitchen
|
|
|
275
275
|
color: Color::COLORS[index % Color::COLORS.size].to_sym,
|
|
276
276
|
logdev: log_location,
|
|
277
277
|
level: Util.to_logger_level(log_level),
|
|
278
|
-
log_overwrite
|
|
278
|
+
log_overwrite:,
|
|
279
279
|
progname: name,
|
|
280
280
|
colorize: @colorize
|
|
281
281
|
)
|
data/lib/kitchen/configurable.rb
CHANGED
|
@@ -241,7 +241,7 @@ module Kitchen
|
|
|
241
241
|
#{deprecated_config.keys.join("\n")}
|
|
242
242
|
Run 'kitchen doctor' for details.
|
|
243
243
|
MSG
|
|
244
|
-
|
|
244
|
+
Error.warn_on_stderr(warning)
|
|
245
245
|
|
|
246
246
|
# Set global var that the deprecation message has been printed
|
|
247
247
|
@@has_been_warned_of_deprecations = true
|
|
@@ -70,7 +70,7 @@ module Kitchen
|
|
|
70
70
|
def converge(state) # rubocop:disable Metrics/AbcSize
|
|
71
71
|
provisioner = instance.provisioner
|
|
72
72
|
provisioner.create_sandbox
|
|
73
|
-
sandbox_dirs =
|
|
73
|
+
sandbox_dirs = provisioner.sandbox_dirs
|
|
74
74
|
|
|
75
75
|
instance.transport.connection(backcompat_merged_state(state)) do |conn|
|
|
76
76
|
conn.execute(env_cmd(provisioner.install_command))
|
|
@@ -299,7 +299,7 @@ module Kitchen
|
|
|
299
299
|
# @param options [Hash] configuration hash (default: `{}`)
|
|
300
300
|
# @api private
|
|
301
301
|
def wait_for_sshd(hostname, username = nil, options = {})
|
|
302
|
-
pseudo_state = { hostname:
|
|
302
|
+
pseudo_state = { hostname: }
|
|
303
303
|
pseudo_state[:username] = username if username
|
|
304
304
|
pseudo_state.merge!(options)
|
|
305
305
|
|
data/lib/kitchen/errors.rb
CHANGED
|
@@ -94,6 +94,19 @@ module Kitchen
|
|
|
94
94
|
"".center(22, "-"),
|
|
95
95
|
]
|
|
96
96
|
end
|
|
97
|
+
|
|
98
|
+
# Log a warn message on STDERR device.
|
|
99
|
+
# This will help to distinguish between the errors and
|
|
100
|
+
# output when parsing the output from the commands like
|
|
101
|
+
# kitchen diagnose.
|
|
102
|
+
#
|
|
103
|
+
# @params lines [Array<String>] Array of lines that needs to be printed
|
|
104
|
+
def self.warn_on_stderr(lines)
|
|
105
|
+
Array(lines).each do |line|
|
|
106
|
+
line = Color.colorize(line, :blue) if Kitchen.tty?
|
|
107
|
+
$stderr.puts(line)
|
|
108
|
+
end
|
|
109
|
+
end
|
|
97
110
|
end
|
|
98
111
|
|
|
99
112
|
# Base exception class from which all Kitchen exceptions derive. This class
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
require_relative "../platform_filter"
|
|
2
|
+
|
|
1
3
|
module Kitchen
|
|
2
4
|
class LifecycleHook
|
|
3
5
|
class Base
|
|
@@ -59,14 +61,14 @@ module Kitchen
|
|
|
59
61
|
lifecycle_hooks.state_file
|
|
60
62
|
end
|
|
61
63
|
|
|
62
|
-
# @return [Array<
|
|
64
|
+
# @return [Array<PlatformFilter>] names of excluded platforms
|
|
63
65
|
def excludes
|
|
64
|
-
@excludes ||= hook.fetch(:excludes, [])
|
|
66
|
+
@excludes ||= PlatformFilter.convert(hook.fetch(:excludes, []))
|
|
65
67
|
end
|
|
66
68
|
|
|
67
|
-
# @return [Array<
|
|
69
|
+
# @return [Array<PlatformFilter>] names of only included platforms
|
|
68
70
|
def includes
|
|
69
|
-
@includes ||= hook.fetch(:includes, [])
|
|
71
|
+
@includes ||= PlatformFilter.convert(hook.fetch(:includes, []))
|
|
70
72
|
end
|
|
71
73
|
|
|
72
74
|
# @return [String]
|
|
@@ -46,6 +46,8 @@ module Kitchen
|
|
|
46
46
|
run(phase, :pre)
|
|
47
47
|
yield
|
|
48
48
|
run(phase, :post)
|
|
49
|
+
ensure
|
|
50
|
+
run(phase, :finally)
|
|
49
51
|
end
|
|
50
52
|
|
|
51
53
|
# @return [Kitchen::StateFile]
|
|
@@ -56,7 +58,7 @@ module Kitchen
|
|
|
56
58
|
# Execute a specific lifecycle hook.
|
|
57
59
|
#
|
|
58
60
|
# @param phase [String] Lifecycle phase which is being executed.
|
|
59
|
-
# @param hook_timing [Symbol] `:pre
|
|
61
|
+
# @param hook_timing [Symbol] `:pre`, `:post`, or `:finally` to indicate which hook to run.
|
|
60
62
|
# @return [void]
|
|
61
63
|
def run(phase, hook_timing)
|
|
62
64
|
# Yes this has to be a symbol because of how data munger works.
|
data/lib/kitchen/loader/yaml.rb
CHANGED
|
@@ -352,14 +352,7 @@ module Kitchen
|
|
|
352
352
|
def parse_yaml_string(string, file_name)
|
|
353
353
|
return {} if string.nil? || string.empty?
|
|
354
354
|
|
|
355
|
-
result =
|
|
356
|
-
if Gem::Requirement.new(">= 3.1.0").satisfied_by?(Gem::Version.new(Psych::VERSION))
|
|
357
|
-
# ruby >= 2.6.0
|
|
358
|
-
::YAML.safe_load(string, permitted_classes: [Symbol], permitted_symbols: [], aliases: true) || {}
|
|
359
|
-
else
|
|
360
|
-
# ruby < 2.6.0
|
|
361
|
-
::YAML.safe_load(string, [Symbol], [], true) || {}
|
|
362
|
-
end
|
|
355
|
+
result = ::YAML.safe_load(string, permitted_classes: [Symbol], permitted_symbols: [], aliases: true) || {}
|
|
363
356
|
unless result.is_a?(Hash)
|
|
364
357
|
raise UserError, "Error parsing #{file_name} as YAML " \
|
|
365
358
|
"(Result of parse was not a Hash, but was a #{result.class}).\n" \
|
data/lib/kitchen/platform.rb
CHANGED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Author:: Baptiste Courtois (<b.courtois@criteo.com>)
|
|
3
|
+
#
|
|
4
|
+
# Copyright (C) 2021, Baptiste Courtois
|
|
5
|
+
#
|
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
# you may not use this file except in compliance with the License.
|
|
8
|
+
# You may obtain a copy of the License at
|
|
9
|
+
#
|
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
#
|
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
# See the License for the specific language governing permissions and
|
|
16
|
+
# limitations under the License.
|
|
17
|
+
|
|
18
|
+
module Kitchen
|
|
19
|
+
# A wrapper on Regexp and strings to mix them in platform filters.
|
|
20
|
+
#
|
|
21
|
+
# This should handle backward compatibility in most cases were
|
|
22
|
+
# platform are matched against a filters array using Array.include?
|
|
23
|
+
#
|
|
24
|
+
# This wrapper does not work if filters arrays are converted to Set.
|
|
25
|
+
#
|
|
26
|
+
# @author Baptiste Courtois <b.courtois@criteo.com>
|
|
27
|
+
class PlatformFilter
|
|
28
|
+
# Pattern used to determine whether a filter should be handled as a Regexp
|
|
29
|
+
REGEXP_LIKE_PATTERN = %r{^/(?<pattern>.*)/(?<options>[ix]*)$}
|
|
30
|
+
|
|
31
|
+
# Converts platform filters into an array of PlatformFilter handling both strings and Regexp.
|
|
32
|
+
# A string "looks-like" a regexp if it starts by / and end by / + Regexp options i or x
|
|
33
|
+
#
|
|
34
|
+
# @return [Array] filters with regexp-like string converted to PlatformRegexpFilter
|
|
35
|
+
def self.convert(filters)
|
|
36
|
+
::Kernel.Array(filters).map do |filter|
|
|
37
|
+
if (match = filter.match(REGEXP_LIKE_PATTERN))
|
|
38
|
+
options = match["options"].include?("i") ? ::Regexp::IGNORECASE : 0
|
|
39
|
+
options |= ::Regexp::EXTENDED if match["options"].include?("x")
|
|
40
|
+
filter = ::Regexp.new(match["pattern"], options)
|
|
41
|
+
end
|
|
42
|
+
new(filter)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# @return [Regexp] value of this filter
|
|
47
|
+
attr_reader :value
|
|
48
|
+
|
|
49
|
+
# Constructs a new filter.
|
|
50
|
+
#
|
|
51
|
+
# @param [Regexp,String] value of the filter
|
|
52
|
+
def initialize(value)
|
|
53
|
+
raise ::ArgumentError, "PlatformFilter#new requires value to be a String or a Regexp" unless value.is_a?(::Regexp) || value.is_a?(::String)
|
|
54
|
+
|
|
55
|
+
@value = value
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Override of the equality operator to check whether the wrapped Regexp match the given object.
|
|
59
|
+
#
|
|
60
|
+
# @param [Object] other object to compare to
|
|
61
|
+
# @return [Boolean] whether the objects are equal or the wrapped Regexp matches the given string or symbol
|
|
62
|
+
def ==(other)
|
|
63
|
+
if @value.is_a?(::Regexp) && (other.is_a?(::String) || other.is_a?(::Symbol))
|
|
64
|
+
@value =~ other
|
|
65
|
+
else
|
|
66
|
+
other == @value
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
alias eq? ==
|
|
71
|
+
end
|
|
72
|
+
end
|
data/lib/kitchen/plugin_base.rb
CHANGED
|
@@ -70,7 +70,6 @@ module Kitchen
|
|
|
70
70
|
# rubocop:disable Metrics/AbcSize
|
|
71
71
|
def call(state)
|
|
72
72
|
create_sandbox
|
|
73
|
-
sandbox_dirs = Util.list_directory(sandbox_path)
|
|
74
73
|
|
|
75
74
|
instance.transport.connection(state) do |conn|
|
|
76
75
|
config[:uploads].to_h.each do |locals, remote|
|
|
@@ -182,6 +181,13 @@ module Kitchen
|
|
|
182
181
|
"trying to access the path."
|
|
183
182
|
end
|
|
184
183
|
|
|
184
|
+
# Returns the list of items in the sandbox directory
|
|
185
|
+
#
|
|
186
|
+
# @return [String] path of items in the sandbox directory
|
|
187
|
+
def sandbox_dirs
|
|
188
|
+
Util.list_directory(sandbox_path)
|
|
189
|
+
end
|
|
190
|
+
|
|
185
191
|
# Deletes the sandbox path. Without calling this method, the sandbox path
|
|
186
192
|
# will persist after the process terminates. In other words, cleanup is
|
|
187
193
|
# explicit. This method is safe to call multiple times.
|
|
@@ -287,16 +287,17 @@ module Kitchen
|
|
|
287
287
|
def update_dna_for_policyfile
|
|
288
288
|
policy = Chef::Policyfile.new(
|
|
289
289
|
policyfile, sandbox_path,
|
|
290
|
-
logger
|
|
290
|
+
logger:,
|
|
291
291
|
always_update: config[:always_update_cookbooks],
|
|
292
|
-
policy_group
|
|
292
|
+
policy_group:,
|
|
293
|
+
license: config[:chef_license]
|
|
293
294
|
)
|
|
294
295
|
Kitchen.mutex.synchronize do
|
|
295
296
|
policy.compile
|
|
296
297
|
end
|
|
297
298
|
policy_name = JSON.parse(IO.read(policy.lockfile))["name"]
|
|
298
299
|
policy_group = config[:policy_group] || "local"
|
|
299
|
-
config[:attributes].merge(policy_name
|
|
300
|
+
config[:attributes].merge(policy_name:, policy_group:)
|
|
300
301
|
end
|
|
301
302
|
|
|
302
303
|
# Performs a Policyfile cookbook resolution inside a common mutex.
|
|
@@ -306,9 +307,10 @@ module Kitchen
|
|
|
306
307
|
Kitchen.mutex.synchronize do
|
|
307
308
|
Chef::Policyfile.new(
|
|
308
309
|
policyfile, sandbox_path,
|
|
309
|
-
logger
|
|
310
|
+
logger:,
|
|
310
311
|
always_update: config[:always_update_cookbooks],
|
|
311
|
-
policy_group: config[:policy_group]
|
|
312
|
+
policy_group: config[:policy_group],
|
|
313
|
+
license: config[:chef_license]
|
|
312
314
|
).resolve
|
|
313
315
|
end
|
|
314
316
|
end
|
|
@@ -319,7 +321,7 @@ module Kitchen
|
|
|
319
321
|
def resolve_with_berkshelf
|
|
320
322
|
Kitchen.mutex.synchronize do
|
|
321
323
|
Chef::Berkshelf.new(berksfile, tmpbooks_dir,
|
|
322
|
-
logger
|
|
324
|
+
logger:,
|
|
323
325
|
always_update: config[:always_update_cookbooks]).resolve
|
|
324
326
|
end
|
|
325
327
|
end
|
|
@@ -41,12 +41,13 @@ module Kitchen
|
|
|
41
41
|
# cookbooks
|
|
42
42
|
# @param logger [Kitchen::Logger] a logger to use for output, defaults
|
|
43
43
|
# to `Kitchen.logger`
|
|
44
|
-
def initialize(policyfile, path, logger: Kitchen.logger, always_update: false, policy_group: nil)
|
|
44
|
+
def initialize(policyfile, path, license: nil, logger: Kitchen.logger, always_update: false, policy_group: nil)
|
|
45
45
|
@policyfile = policyfile
|
|
46
46
|
@path = path
|
|
47
47
|
@logger = logger
|
|
48
48
|
@always_update = always_update
|
|
49
49
|
@policy_group = policy_group
|
|
50
|
+
@license = license
|
|
50
51
|
end
|
|
51
52
|
|
|
52
53
|
# Loads the library code required to use the resolver.
|
|
@@ -62,10 +63,10 @@ module Kitchen
|
|
|
62
63
|
def resolve
|
|
63
64
|
if policy_group
|
|
64
65
|
info("Exporting cookbook dependencies from Policyfile #{path} with policy_group #{policy_group} using `#{cli_path} export`...")
|
|
65
|
-
run_command("#{cli_path} export #{escape_path(policyfile)} #{escape_path(path)} --policy_group #{policy_group} --force")
|
|
66
|
+
run_command("#{cli_path} export #{escape_path(policyfile)} #{escape_path(path)} --policy_group #{policy_group} --force --chef-license #{license}")
|
|
66
67
|
else
|
|
67
68
|
info("Exporting cookbook dependencies from Policyfile #{path} using `#{cli_path} export`...")
|
|
68
|
-
run_command("#{cli_path} export #{escape_path(policyfile)} #{escape_path(path)} --force")
|
|
69
|
+
run_command("#{cli_path} export #{escape_path(policyfile)} #{escape_path(path)} --force --chef-license #{license}")
|
|
69
70
|
end
|
|
70
71
|
end
|
|
71
72
|
|
|
@@ -77,11 +78,11 @@ module Kitchen
|
|
|
77
78
|
else
|
|
78
79
|
info("Policy lock file doesn't exist, running `#{cli_path} install` for Policyfile #{policyfile}...")
|
|
79
80
|
end
|
|
80
|
-
run_command("#{cli_path} install #{escape_path(policyfile)}")
|
|
81
|
+
run_command("#{cli_path} install #{escape_path(policyfile)} --chef-license #{license}")
|
|
81
82
|
|
|
82
83
|
if always_update
|
|
83
84
|
info("Updating policy lock using `#{cli_path} update`")
|
|
84
|
-
run_command("#{cli_path} update #{escape_path(policyfile)}")
|
|
85
|
+
run_command("#{cli_path} update #{escape_path(policyfile)} --chef-license #{license}")
|
|
85
86
|
end
|
|
86
87
|
end
|
|
87
88
|
|
|
@@ -114,6 +115,10 @@ module Kitchen
|
|
|
114
115
|
# @api private
|
|
115
116
|
attr_reader :policy_group
|
|
116
117
|
|
|
118
|
+
# @return [String] name of the chef_license
|
|
119
|
+
# @api private
|
|
120
|
+
attr_reader :license
|
|
121
|
+
|
|
117
122
|
# Escape spaces in a path in way that works with both Sh (Unix) and
|
|
118
123
|
# Windows.
|
|
119
124
|
#
|
|
@@ -152,11 +157,10 @@ module Kitchen
|
|
|
152
157
|
def no_cli_found_error
|
|
153
158
|
@logger.fatal("The `chef` or `chef-cli` executables cannot be found in your " \
|
|
154
159
|
"PATH. Ensure you have installed Chef Workstation " \
|
|
155
|
-
"from https://
|
|
160
|
+
"from https://www.chef.io/downloads/ and that your PATH " \
|
|
156
161
|
"setting includes the path to the `chef` or `chef-cli` commands.")
|
|
157
162
|
raise UserError, "Could not find the chef or chef-cli executables in your PATH."
|
|
158
163
|
end
|
|
159
|
-
|
|
160
164
|
end
|
|
161
165
|
end
|
|
162
166
|
end
|
|
@@ -69,7 +69,7 @@ module Kitchen
|
|
|
69
69
|
README.* VERSION metadata.{json,rb} attributes.rb recipe.rb
|
|
70
70
|
attributes/**/* definitions/**/* files/**/* libraries/**/*
|
|
71
71
|
providers/**/* recipes/**/* resources/**/* templates/**/*
|
|
72
|
-
ohai/**/*
|
|
72
|
+
ohai/**/* compliance/**/*
|
|
73
73
|
).join(",")
|
|
74
74
|
# to ease upgrades, allow the user to turn deprecation warnings into errors
|
|
75
75
|
default_config :deprecations_as_errors, false
|
|
@@ -210,7 +210,7 @@ module Kitchen
|
|
|
210
210
|
|
|
211
211
|
deprecate_config_for :install_msi_url, Util.outdent!(<<-MSG)
|
|
212
212
|
The 'install_msi_url' will be relaced by the 'download_url' attribute.
|
|
213
|
-
'download_url' will be applied to Bourne and
|
|
213
|
+
'download_url' will be applied to Bourne and PowerShell download scripts.
|
|
214
214
|
|
|
215
215
|
Note: 'product_name' must be set in order to use 'download_url'
|
|
216
216
|
until 'product_name' replaces 'require_chef_omnibus' as the default.
|
|
@@ -347,7 +347,7 @@ module Kitchen
|
|
|
347
347
|
omnibus_url: config[:chef_omnibus_url],
|
|
348
348
|
project: project.nil? ? nil : project[1],
|
|
349
349
|
install_flags: config[:chef_omnibus_install_options],
|
|
350
|
-
sudo_command
|
|
350
|
+
sudo_command:,
|
|
351
351
|
}.tap do |opts|
|
|
352
352
|
opts[:root] = config[:chef_omnibus_root] if config.key? :chef_omnibus_root
|
|
353
353
|
%i{install_msi_url http_proxy https_proxy}.each do |key|
|
|
@@ -482,10 +482,10 @@ module Kitchen
|
|
|
482
482
|
super
|
|
483
483
|
if File.exist?(policyfile)
|
|
484
484
|
debug("Policyfile found at #{policyfile}, using Policyfile to resolve cookbook dependencies")
|
|
485
|
-
Chef::Policyfile.load!(logger:
|
|
485
|
+
Chef::Policyfile.load!(logger:)
|
|
486
486
|
elsif File.exist?(berksfile)
|
|
487
487
|
debug("Berksfile found at #{berksfile}, using Berkshelf to resolve cookbook dependencies")
|
|
488
|
-
Chef::Berkshelf.load!(logger:
|
|
488
|
+
Chef::Berkshelf.load!(logger:)
|
|
489
489
|
end
|
|
490
490
|
end
|
|
491
491
|
|
|
@@ -681,25 +681,42 @@ module Kitchen
|
|
|
681
681
|
chef_cmds(base_cmd).join(separator)
|
|
682
682
|
end
|
|
683
683
|
|
|
684
|
-
# Gives an array of
|
|
684
|
+
# Gives an array of commands
|
|
685
685
|
# @api private
|
|
686
686
|
def chef_cmds(base_cmd)
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
if config[:enforce_idempotency]
|
|
695
|
-
idempotent_cmd = prefix_command(wrap_shell_code(
|
|
696
|
-
[base_cmd, *chef_args("client_no_updated_resources.rb"), last_exit_code].join(" ")
|
|
697
|
-
.tap { |str| str.insert(0, reload_ps1_path) if windows_os? }
|
|
698
|
-
))
|
|
699
|
-
cmds[-1] = idempotent_cmd
|
|
687
|
+
cmds = []
|
|
688
|
+
num_converges = config[:multiple_converge].to_i
|
|
689
|
+
idempotency = config[:enforce_idempotency]
|
|
690
|
+
|
|
691
|
+
# Execute Chef Client n-1 times, without exiting
|
|
692
|
+
(num_converges - 1).times do
|
|
693
|
+
cmds << wrapped_chef_cmd(base_cmd, config_filename)
|
|
700
694
|
end
|
|
695
|
+
|
|
696
|
+
# Append another execution with Windows specific Exit code helper or (for
|
|
697
|
+
# idempotency check) a specific config file which assures no changed resources.
|
|
698
|
+
cmds << unless idempotency
|
|
699
|
+
wrapped_chef_cmd(base_cmd, config_filename, append: last_exit_code)
|
|
700
|
+
else
|
|
701
|
+
wrapped_chef_cmd(base_cmd, "client_no_updated_resources.rb", append: last_exit_code)
|
|
702
|
+
end
|
|
701
703
|
cmds
|
|
702
704
|
end
|
|
705
|
+
|
|
706
|
+
# Concatenate all arguments and wrap it with shell-specifics
|
|
707
|
+
# @api private
|
|
708
|
+
def wrapped_chef_cmd(base_cmd, configfile, append: "")
|
|
709
|
+
args = []
|
|
710
|
+
|
|
711
|
+
args << base_cmd
|
|
712
|
+
args << chef_args(configfile)
|
|
713
|
+
args << append
|
|
714
|
+
|
|
715
|
+
shell_cmd = args.flatten.join(" ")
|
|
716
|
+
shell_cmd = shell_cmd.prepend(reload_ps1_path) if windows_os?
|
|
717
|
+
|
|
718
|
+
prefix_command(wrap_shell_code(shell_cmd))
|
|
719
|
+
end
|
|
703
720
|
end
|
|
704
721
|
end
|
|
705
722
|
end
|
data/lib/kitchen/ssh.rb
CHANGED
|
@@ -23,6 +23,7 @@ require "socket" unless defined?(Socket)
|
|
|
23
23
|
|
|
24
24
|
require_relative "errors"
|
|
25
25
|
require_relative "login_command"
|
|
26
|
+
require_relative "util"
|
|
26
27
|
|
|
27
28
|
module Kitchen
|
|
28
29
|
# Wrapped exception for any internally raised SSH-related errors.
|
|
@@ -75,7 +76,9 @@ module Kitchen
|
|
|
75
76
|
# @param cmd [String] command string to execute
|
|
76
77
|
# @raise [SSHFailed] if the command does not exit with a 0 code
|
|
77
78
|
def exec(cmd)
|
|
78
|
-
|
|
79
|
+
string_to_mask = "[SSH] #{self} (#{cmd})"
|
|
80
|
+
masked_string = Util.mask_values(string_to_mask, %w{password ssh_http_proxy_password})
|
|
81
|
+
logger.debug(masked_string)
|
|
79
82
|
exit_code = exec_with_exit(cmd)
|
|
80
83
|
|
|
81
84
|
if exit_code != 0
|
|
@@ -137,7 +140,9 @@ module Kitchen
|
|
|
137
140
|
def shutdown
|
|
138
141
|
return if @session.nil?
|
|
139
142
|
|
|
140
|
-
|
|
143
|
+
string_to_mask = "[SSH] closing connection to #{self}"
|
|
144
|
+
masked_string = Util.mask_values(string_to_mask, %w{password ssh_http_proxy_password})
|
|
145
|
+
logger.debug(masked_string)
|
|
141
146
|
session.shutdown!
|
|
142
147
|
ensure
|
|
143
148
|
@session = nil
|
|
@@ -212,7 +217,9 @@ module Kitchen
|
|
|
212
217
|
retries = options[:ssh_retries] || 3
|
|
213
218
|
|
|
214
219
|
begin
|
|
215
|
-
|
|
220
|
+
string_to_mask = "[SSH] opening connection to #{self}"
|
|
221
|
+
masked_string = Util.mask_values(string_to_mask, %w{password ssh_http_proxy_password})
|
|
222
|
+
logger.debug(masked_string)
|
|
216
223
|
Net::SSH.start(hostname, username, options)
|
|
217
224
|
rescue *rescue_exceptions => e
|
|
218
225
|
retries -= 1
|
data/lib/kitchen/suite.rb
CHANGED
|
@@ -15,6 +15,8 @@
|
|
|
15
15
|
# See the License for the specific language governing permissions and
|
|
16
16
|
# limitations under the License.
|
|
17
17
|
|
|
18
|
+
require_relative "platform_filter"
|
|
19
|
+
|
|
18
20
|
module Kitchen
|
|
19
21
|
# A logical configuration representing a test case or fixture that will be
|
|
20
22
|
# executed on a platform.
|
|
@@ -41,8 +43,8 @@ module Kitchen
|
|
|
41
43
|
@name = options.fetch(:name) do
|
|
42
44
|
raise ClientError, "Suite#new requires option :name"
|
|
43
45
|
end
|
|
44
|
-
@excludes = options.fetch(:excludes, [])
|
|
45
|
-
@includes = options.fetch(:includes, [])
|
|
46
|
+
@excludes = PlatformFilter.convert(options.fetch(:excludes, []))
|
|
47
|
+
@includes = PlatformFilter.convert(options.fetch(:includes, []))
|
|
46
48
|
end
|
|
47
49
|
end
|
|
48
50
|
end
|
|
@@ -128,8 +128,8 @@ module Kitchen
|
|
|
128
128
|
tries += 1
|
|
129
129
|
debug("Attempting to execute command - try #{tries} of #{max_retries}.")
|
|
130
130
|
execute(command)
|
|
131
|
-
rescue
|
|
132
|
-
if retry?(tries, max_retries, retryable_exit_codes, e
|
|
131
|
+
rescue Exception => e
|
|
132
|
+
if retry?(tries, max_retries, retryable_exit_codes, e)
|
|
133
133
|
close
|
|
134
134
|
sleep wait_time
|
|
135
135
|
retry
|
|
@@ -139,10 +139,14 @@ module Kitchen
|
|
|
139
139
|
end
|
|
140
140
|
end
|
|
141
141
|
|
|
142
|
-
def retry?(current_try, max_retries, retryable_exit_codes,
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
142
|
+
def retry?(current_try, max_retries, retryable_exit_codes, exception)
|
|
143
|
+
if exception.is_a?(Kitchen::Transport::TransportFailed)
|
|
144
|
+
return current_try <= max_retries &&
|
|
145
|
+
!retryable_exit_codes.nil? &&
|
|
146
|
+
retryable_exit_codes.flatten.include?(exception.exit_code)
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
false
|
|
146
150
|
end
|
|
147
151
|
|
|
148
152
|
# Builds a LoginCommand which can be used to open an interactive
|