test-kitchen 2.9.0 → 2.12.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 +5 -11
- data/Rakefile +0 -22
- data/lib/kitchen/chef_utils_wiring.rb +40 -0
- data/lib/kitchen/cli.rb +3 -3
- data/lib/kitchen/command/console.rb +1 -1
- data/lib/kitchen/config.rb +7 -4
- data/lib/kitchen/lifecycle_hook/base.rb +78 -0
- data/lib/kitchen/lifecycle_hook/local.rb +53 -0
- data/lib/kitchen/lifecycle_hook/remote.rb +39 -0
- data/lib/kitchen/lifecycle_hooks.rb +26 -78
- data/lib/kitchen/loader/yaml.rb +1 -0
- data/lib/kitchen/logger.rb +2 -2
- data/lib/kitchen/provisioner/base.rb +6 -3
- data/lib/kitchen/provisioner/chef/policyfile.rb +31 -39
- data/lib/kitchen/provisioner/chef_zero.rb +11 -0
- data/lib/kitchen/transport/ssh.rb +8 -10
- data/lib/kitchen/transport/winrm.rb +3 -5
- data/lib/kitchen/verifier/base.rb +1 -3
- data/lib/kitchen/verifier/shell.rb +1 -0
- data/lib/kitchen/version.rb +1 -1
- data/lib/kitchen/which.rb +26 -0
- data/test-kitchen.gemspec +2 -1
- metadata +23 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fc041ba149f1e4bec89f846b40d1888dda814d55a1b7968f2c4a37d8cd6ab890
|
4
|
+
data.tar.gz: 3c5ce6235b30e8e28182218c04d683b96a6e662a95c817bba78bac6d2c59aa38
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d17c171f8baa2ea8730d5c27f5c1e428f1a71e1b584e95ca76f46e181444261eeef54fd39c2268efe3aaa17bac01948294786184bc11990221009a930a08bd91
|
7
|
+
data.tar.gz: 9bc7a23f2f43be47f37bef8fac6de614c41038033038476a4110ebfb61925955fe0512c517e6ea2929b3664ee379aceb8594bf943001514ffaec2612aa2c80ad
|
data/Gemfile
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
source "https://rubygems.org"
|
2
|
+
|
3
|
+
# Specify your gem"s dependencies in test-kitchen.gemspec
|
2
4
|
gemspec
|
3
5
|
|
4
6
|
group :integration do
|
@@ -8,20 +10,12 @@ group :integration do
|
|
8
10
|
gem "kitchen-vagrant"
|
9
11
|
end
|
10
12
|
|
11
|
-
group :changelog do
|
12
|
-
gem "github_changelog_generator", "1.15.2"
|
13
|
-
end
|
14
|
-
|
15
13
|
group :debug do
|
16
|
-
gem "pry"
|
14
|
+
gem "pry", "~>0.12"
|
17
15
|
gem "pry-byebug"
|
18
16
|
gem "pry-stack_explorer"
|
19
17
|
end
|
20
18
|
|
21
19
|
group :chefstyle do
|
22
|
-
gem "chefstyle"
|
23
|
-
end
|
24
|
-
|
25
|
-
group :docs do
|
26
|
-
gem "yard"
|
27
|
-
end
|
20
|
+
gem "chefstyle", "2.0.4"
|
21
|
+
end
|
data/Rakefile
CHANGED
@@ -41,30 +41,8 @@ end
|
|
41
41
|
desc "Run all quality tasks"
|
42
42
|
task quality: %i{style stats}
|
43
43
|
|
44
|
-
begin
|
45
|
-
require "yard" unless defined?(YARD)
|
46
|
-
YARD::Rake::YardocTask.new
|
47
|
-
rescue LoadError
|
48
|
-
puts "yard is not available. (sudo) gem install yard to generate yard documentation."
|
49
|
-
end
|
50
|
-
|
51
44
|
task default: %i{test quality}
|
52
45
|
|
53
|
-
begin
|
54
|
-
require "github_changelog_generator/task"
|
55
|
-
require "kitchen/version"
|
56
|
-
|
57
|
-
GitHubChangelogGenerator::RakeTask.new :changelog do |config|
|
58
|
-
config.future_release = "v#{Kitchen::VERSION}"
|
59
|
-
config.enhancement_labels = "enhancement,Enhancement,New Feature,Feature,Improvement".split(",")
|
60
|
-
config.bug_labels = "bug,Bug".split(",")
|
61
|
-
config.exclude_labels = %w{Duplicate Question Discussion No_Changelog}
|
62
|
-
end
|
63
|
-
rescue LoadError
|
64
|
-
puts "github_changelog_generator is not available." \
|
65
|
-
" (sudo) gem install github_changelog_generator to generate changelogs"
|
66
|
-
end
|
67
|
-
|
68
46
|
namespace :docs do
|
69
47
|
desc "Deploy docs"
|
70
48
|
task :deploy do
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
#
|
3
|
+
# Copyright:: Copyright (c) Chef Software Inc.
|
4
|
+
# License:: Apache License, Version 2.0
|
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
|
+
|
19
|
+
module Kitchen
|
20
|
+
# Common Dependency Injection wiring for ChefUtils-related modules
|
21
|
+
module ChefUtilsWiring
|
22
|
+
private
|
23
|
+
|
24
|
+
def __config
|
25
|
+
# this would need to be some kind of Chef::Config looking thing, which probably requires
|
26
|
+
# a translation object from t-k config to Chef::Config layout if that ever becomes necessary.
|
27
|
+
# this ISNT the t-k config.
|
28
|
+
{}
|
29
|
+
end
|
30
|
+
|
31
|
+
def __log
|
32
|
+
@logger
|
33
|
+
end
|
34
|
+
|
35
|
+
def __transport_connection
|
36
|
+
# this could be wired up to train at some point, but need to be careful because about local vs. remote
|
37
|
+
# uses of helpers with test-kitchen, right now we're using it for local.
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/lib/kitchen/cli.rb
CHANGED
@@ -162,7 +162,7 @@ module Kitchen
|
|
162
162
|
long_desc <<-DESC
|
163
163
|
The instance states are in order: destroy, create, converge, setup, verify, destroy.
|
164
164
|
Change one or more instances from the current state to the #{action} state. Actions for all
|
165
|
-
intermediate states will be executed. See
|
165
|
+
intermediate states will be executed. See https://kitchen.ci/ for further explanation.
|
166
166
|
DESC
|
167
167
|
method_option :concurrency,
|
168
168
|
aliases: "-c",
|
@@ -285,7 +285,7 @@ module Kitchen
|
|
285
285
|
perform("exec", "exec", args)
|
286
286
|
end
|
287
287
|
|
288
|
-
desc "version", "Print Kitchen's version information"
|
288
|
+
desc "version", "Print Test Kitchen's version information"
|
289
289
|
def version
|
290
290
|
puts "Test Kitchen version #{Kitchen::VERSION}"
|
291
291
|
end
|
@@ -296,7 +296,7 @@ module Kitchen
|
|
296
296
|
perform("sink", "sink")
|
297
297
|
end
|
298
298
|
|
299
|
-
desc "console", "Kitchen Console!"
|
299
|
+
desc "console", "Test Kitchen Console!"
|
300
300
|
def console
|
301
301
|
perform("console", "console")
|
302
302
|
end
|
data/lib/kitchen/config.rb
CHANGED
@@ -244,16 +244,18 @@ module Kitchen
|
|
244
244
|
# @return [Instance] a new Instance object
|
245
245
|
# @api private
|
246
246
|
def new_instance(suite, platform, index)
|
247
|
+
sf = new_state_file(suite, platform)
|
248
|
+
|
247
249
|
Instance.new(
|
248
250
|
driver: new_driver(suite, platform),
|
249
|
-
lifecycle_hooks: new_lifecycle_hooks(suite, platform),
|
251
|
+
lifecycle_hooks: new_lifecycle_hooks(suite, platform, sf),
|
250
252
|
logger: new_instance_logger(suite, platform, index),
|
251
253
|
suite: suite,
|
252
254
|
platform: platform,
|
253
255
|
provisioner: new_provisioner(suite, platform),
|
254
256
|
transport: new_transport(suite, platform),
|
255
257
|
verifier: new_verifier(suite, platform),
|
256
|
-
state_file:
|
258
|
+
state_file: sf
|
257
259
|
)
|
258
260
|
end
|
259
261
|
|
@@ -284,11 +286,12 @@ module Kitchen
|
|
284
286
|
#
|
285
287
|
# @param suite [Suite,#name] a Suite
|
286
288
|
# @param platform [Platform,#name] a Platform
|
289
|
+
# @param state_file [Kitchen::StateFile] a SateFile
|
287
290
|
# @return [LifecycleHooks] a new LifecycleHooks object
|
288
291
|
# @api private
|
289
|
-
def new_lifecycle_hooks(suite, platform)
|
292
|
+
def new_lifecycle_hooks(suite, platform, state_file)
|
290
293
|
lhdata = data.lifecycle_hooks_data_for(suite.name, platform.name)
|
291
|
-
LifecycleHooks.new(lhdata)
|
294
|
+
LifecycleHooks.new(lhdata, state_file)
|
292
295
|
end
|
293
296
|
|
294
297
|
# Builds a newly configured Provisioner object, for a given Suite and
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module Kitchen
|
2
|
+
class LifecycleHook
|
3
|
+
class Base
|
4
|
+
# @return [Kitchen::LifecycleHooks]
|
5
|
+
attr_reader :lifecycle_hooks
|
6
|
+
|
7
|
+
# return [String]
|
8
|
+
attr_reader :phase
|
9
|
+
|
10
|
+
# return [Hash]
|
11
|
+
attr_reader :hook
|
12
|
+
|
13
|
+
# @param lifecycle_hooks [Kitchen::LifecycleHooks]
|
14
|
+
# @param phase [String]
|
15
|
+
# @param hook [Hash]
|
16
|
+
def initialize(lifecycle_hooks, phase, hook)
|
17
|
+
@lifecycle_hooks = lifecycle_hooks
|
18
|
+
@phase = phase
|
19
|
+
@hook = hook
|
20
|
+
end
|
21
|
+
|
22
|
+
# return [void]
|
23
|
+
def run
|
24
|
+
raise NotImplementedError
|
25
|
+
end
|
26
|
+
|
27
|
+
# @return [TrueClass, FalseClass]
|
28
|
+
def should_run?
|
29
|
+
if !includes.empty?
|
30
|
+
includes.include?(platform_name)
|
31
|
+
elsif !excludes.empty?
|
32
|
+
!excludes.include?(platform_name)
|
33
|
+
else
|
34
|
+
true
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# @return [Logger] the lifecycle hooks's logger
|
39
|
+
# otherwise
|
40
|
+
# @api private
|
41
|
+
def logger
|
42
|
+
lifecycle_hooks.send(:logger)
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
# @return [Kitchen::Instance]
|
48
|
+
def instance
|
49
|
+
lifecycle_hooks.instance
|
50
|
+
end
|
51
|
+
|
52
|
+
# @return [Hash]
|
53
|
+
def config
|
54
|
+
lifecycle_hooks.send(:config)
|
55
|
+
end
|
56
|
+
|
57
|
+
# @return [Kitchen::StateFile]
|
58
|
+
def state_file
|
59
|
+
lifecycle_hooks.state_file
|
60
|
+
end
|
61
|
+
|
62
|
+
# @return [Array<String>] names of excluded platforms
|
63
|
+
def excludes
|
64
|
+
@excludes ||= hook.fetch(:excludes, [])
|
65
|
+
end
|
66
|
+
|
67
|
+
# @return [Array<String>] names of only included platforms
|
68
|
+
def includes
|
69
|
+
@includes ||= hook.fetch(:includes, [])
|
70
|
+
end
|
71
|
+
|
72
|
+
# @return [String]
|
73
|
+
def platform_name
|
74
|
+
instance.platform.name
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require_relative "base"
|
2
|
+
require_relative "../shell_out"
|
3
|
+
require_relative "../logging"
|
4
|
+
|
5
|
+
module Kitchen
|
6
|
+
class LifecycleHook
|
7
|
+
class Local < Base
|
8
|
+
include ShellOut
|
9
|
+
include Logging
|
10
|
+
|
11
|
+
# Execute a specific local command hook.
|
12
|
+
#
|
13
|
+
# @return [void]
|
14
|
+
def run
|
15
|
+
state = state_file.read
|
16
|
+
# set up empty user variable
|
17
|
+
user = {}
|
18
|
+
# Set up some environment variables with instance info.
|
19
|
+
environment = {
|
20
|
+
"KITCHEN_INSTANCE_NAME" => instance.name,
|
21
|
+
"KITCHEN_SUITE_NAME" => instance.suite.name,
|
22
|
+
"KITCHEN_PLATFORM_NAME" => instance.platform.name,
|
23
|
+
"KITCHEN_INSTANCE_HOSTNAME" => state[:hostname].to_s,
|
24
|
+
}
|
25
|
+
# If the user specified env vars too, fix them up because symbol keys
|
26
|
+
# make mixlib-shellout sad.
|
27
|
+
hook[:environment]&.each do |k, v|
|
28
|
+
environment[k.to_s] = v.to_s
|
29
|
+
end
|
30
|
+
|
31
|
+
# add user to user hash for later merging
|
32
|
+
user[:user] = hook[:user] if hook[:user]
|
33
|
+
|
34
|
+
# Default the cwd to the kitchen root and resolve a relative input cwd against that.
|
35
|
+
cwd = if hook[:cwd]
|
36
|
+
File.expand_path(hook[:cwd], config[:kitchen_root])
|
37
|
+
else
|
38
|
+
config[:kitchen_root]
|
39
|
+
end
|
40
|
+
# Build the options for mixlib-shellout.
|
41
|
+
opts = {}.merge(user).merge(cwd: cwd, environment: environment)
|
42
|
+
run_command(command, opts)
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
# @return [String]
|
48
|
+
def command
|
49
|
+
hook.fetch(:local)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require_relative "base"
|
2
|
+
require_relative "../errors"
|
3
|
+
|
4
|
+
module Kitchen
|
5
|
+
class LifecycleHook
|
6
|
+
class Remote < Base
|
7
|
+
# Execute a specific remote command hook.
|
8
|
+
#
|
9
|
+
# @return [void]
|
10
|
+
def run
|
11
|
+
# Check if we're in a state that makes sense to even try.
|
12
|
+
unless instance.last_action
|
13
|
+
if hook[:skippable]
|
14
|
+
# Just not even trying.
|
15
|
+
return
|
16
|
+
else
|
17
|
+
raise UserError, "Cannot use remote lifecycle hooks during phases when the instance is not available"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
begin
|
22
|
+
conn = instance.transport.connection(state_file.read)
|
23
|
+
conn.execute(command)
|
24
|
+
rescue Kitchen::Transport::SshFailed => e
|
25
|
+
return if hook[:skippable] && e.message.match(/^SSH exited \(\d{1,3}\) for command: \[.+\]$/)
|
26
|
+
|
27
|
+
raise
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
# return [String]
|
34
|
+
def command
|
35
|
+
hook.fetch(:remote)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -15,8 +15,11 @@
|
|
15
15
|
# See the License for the specific language governing permissions and
|
16
16
|
# limitations under the License.
|
17
17
|
|
18
|
+
require_relative "configurable"
|
18
19
|
require_relative "errors"
|
19
|
-
require_relative "
|
20
|
+
require_relative "lifecycle_hook/local"
|
21
|
+
require_relative "lifecycle_hook/remote"
|
22
|
+
require_relative "logging"
|
20
23
|
|
21
24
|
module Kitchen
|
22
25
|
# A helper object used by {Instance} to coordinate lifecycle hook calls from
|
@@ -27,10 +30,10 @@ module Kitchen
|
|
27
30
|
class LifecycleHooks
|
28
31
|
include Configurable
|
29
32
|
include Logging
|
30
|
-
include ShellOut
|
31
33
|
|
32
|
-
def initialize(config)
|
34
|
+
def initialize(config, state_file)
|
33
35
|
init_config(config)
|
36
|
+
@state_file = state_file
|
34
37
|
end
|
35
38
|
|
36
39
|
# Run a lifecycle phase with the pre and post hooks.
|
@@ -40,21 +43,22 @@ module Kitchen
|
|
40
43
|
# @param block [Proc] Block of code implementing the lifecycle phase.
|
41
44
|
# @return [void]
|
42
45
|
def run_with_hooks(phase, state_file, &block)
|
43
|
-
run(
|
46
|
+
run(phase, :pre)
|
44
47
|
yield
|
45
|
-
run(
|
48
|
+
run(phase, :post)
|
46
49
|
end
|
47
50
|
|
51
|
+
# @return [Kitchen::StateFile]
|
52
|
+
attr_reader :state_file
|
53
|
+
|
48
54
|
private
|
49
55
|
|
50
56
|
# Execute a specific lifecycle hook.
|
51
57
|
#
|
52
|
-
# @param instance [Instance] The instance object to run against.
|
53
58
|
# @param phase [String] Lifecycle phase which is being executed.
|
54
|
-
# @param state_file [StateFile] Instance state file object.
|
55
59
|
# @param hook_timing [Symbol] `:pre` or `:post` to indicate which hook to run.
|
56
60
|
# @return [void]
|
57
|
-
def run(
|
61
|
+
def run(phase, hook_timing)
|
58
62
|
# Yes this has to be a symbol because of how data munger works.
|
59
63
|
hook_key = :"#{hook_timing}_#{phase}"
|
60
64
|
# No hooks? We're outta here.
|
@@ -65,80 +69,24 @@ module Kitchen
|
|
65
69
|
# Coerce the common case of a bare string to be a local command. This
|
66
70
|
# is to match the behavior of the old `pre_create_command` semi-hook.
|
67
71
|
hook = { local: hook } if hook.is_a?(String)
|
68
|
-
|
69
|
-
|
70
|
-
run_local_hook(instance, state_file, hook)
|
71
|
-
elsif hook.include?(:remote)
|
72
|
-
# Remote command execution on the test instance.
|
73
|
-
run_remote_hook(instance, state_file, hook)
|
74
|
-
else
|
75
|
-
raise UserError, "Unknown lifecycle hook target #{hook.inspect}"
|
76
|
-
end
|
72
|
+
hook = generate_hook(phase, hook)
|
73
|
+
hook.run if hook.should_run?
|
77
74
|
end
|
78
75
|
end
|
79
76
|
|
80
|
-
#
|
81
|
-
#
|
82
|
-
# @
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
environment = {
|
93
|
-
"KITCHEN_INSTANCE_NAME" => instance.name,
|
94
|
-
"KITCHEN_SUITE_NAME" => instance.suite.name,
|
95
|
-
"KITCHEN_PLATFORM_NAME" => instance.platform.name,
|
96
|
-
"KITCHEN_INSTANCE_HOSTNAME" => state[:hostname].to_s,
|
97
|
-
}
|
98
|
-
# If the user specified env vars too, fix them up because symbol keys
|
99
|
-
# make mixlib-shellout sad.
|
100
|
-
if hook[:environment]
|
101
|
-
hook[:environment].each do |k, v|
|
102
|
-
environment[k.to_s] = v.to_s
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
# add user to user hash for later merging
|
107
|
-
if hook[:user]
|
108
|
-
user[:user] = hook[:user]
|
77
|
+
# @param phase [String]
|
78
|
+
# @param hook [Hash]
|
79
|
+
# @return [Kitchen::LifecycleHook::Local, Kitchen::LifecycleHook::Remote]
|
80
|
+
def generate_hook(phase, hook)
|
81
|
+
if hook.include?(:local)
|
82
|
+
# Local command execution on the workstation.
|
83
|
+
Kitchen::LifecycleHook::Local.new(self, phase, hook)
|
84
|
+
elsif hook.include?(:remote)
|
85
|
+
# Remote command execution on the test instance.
|
86
|
+
Kitchen::LifecycleHook::Remote.new(self, phase, hook)
|
87
|
+
else
|
88
|
+
raise UserError, "Unknown lifecycle hook target #{hook.inspect}"
|
109
89
|
end
|
110
|
-
|
111
|
-
# Default the cwd to the kitchen root and resolve a relative input cwd against that.
|
112
|
-
cwd = if hook[:cwd]
|
113
|
-
File.expand_path(hook[:cwd], config[:kitchen_root])
|
114
|
-
else
|
115
|
-
config[:kitchen_root]
|
116
|
-
end
|
117
|
-
# Build the options for mixlib-shellout.
|
118
|
-
opts = {}.merge(user).merge(cwd: cwd, environment: environment)
|
119
|
-
run_command(cmd, opts)
|
120
|
-
end
|
121
|
-
|
122
|
-
# Execute a specific remote command hook.
|
123
|
-
#
|
124
|
-
# @param instance [Instance] The instance object to run against.
|
125
|
-
# @param state_file [StateFile] Instance state file object.
|
126
|
-
# @param hook [Hash] Hook configration to use.
|
127
|
-
# @return [void]
|
128
|
-
def run_remote_hook(instance, state_file, hook)
|
129
|
-
# Check if we're in a state that makes sense to even try.
|
130
|
-
unless instance.last_action
|
131
|
-
if hook[:skippable]
|
132
|
-
# Just not even trying.
|
133
|
-
return
|
134
|
-
else
|
135
|
-
raise UserError, "Cannot use remote lifecycle hooks during phases when the instance is not available"
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
|
-
cmd = hook.fetch(:remote)
|
140
|
-
conn = instance.transport.connection(state_file.read)
|
141
|
-
conn.execute(cmd)
|
142
90
|
end
|
143
91
|
end
|
144
92
|
end
|
data/lib/kitchen/loader/yaml.rb
CHANGED
data/lib/kitchen/logger.rb
CHANGED
@@ -293,11 +293,11 @@ module Kitchen
|
|
293
293
|
logger = StdoutLogger.new(stdout)
|
294
294
|
if colorize
|
295
295
|
logger.formatter = proc do |_severity, _datetime, _progname, msg|
|
296
|
-
Color.colorize(msg.to_s, color).concat("\n")
|
296
|
+
Color.colorize(msg.dup.to_s, color).concat("\n")
|
297
297
|
end
|
298
298
|
else
|
299
299
|
logger.formatter = proc do |_severity, _datetime, _progname, msg|
|
300
|
-
msg.concat("\n")
|
300
|
+
msg.dup.concat("\n")
|
301
301
|
end
|
302
302
|
end
|
303
303
|
logger
|
@@ -51,6 +51,7 @@ module Kitchen
|
|
51
51
|
|
52
52
|
default_config :command_prefix, nil
|
53
53
|
|
54
|
+
default_config :uploads, {}
|
54
55
|
default_config :downloads, {}
|
55
56
|
|
56
57
|
expand_path_for :test_base_path
|
@@ -72,6 +73,10 @@ module Kitchen
|
|
72
73
|
sandbox_dirs = Util.list_directory(sandbox_path)
|
73
74
|
|
74
75
|
instance.transport.connection(state) do |conn|
|
76
|
+
config[:uploads].to_h.each do |locals, remote|
|
77
|
+
debug("Uploading #{Array(locals).join(", ")} to #{remote}")
|
78
|
+
conn.upload(locals.to_s, remote)
|
79
|
+
end
|
75
80
|
conn.execute(install_command)
|
76
81
|
conn.execute(init_command)
|
77
82
|
info("Transferring files to #{instance.to_str}")
|
@@ -172,11 +177,9 @@ module Kitchen
|
|
172
177
|
# @raise [ClientError] if the sandbox directory has no yet been created
|
173
178
|
# by calling `#create_sandbox`
|
174
179
|
def sandbox_path
|
175
|
-
@sandbox_path ||=
|
176
|
-
raise ClientError, "Sandbox directory has not yet " \
|
180
|
+
@sandbox_path ||= raise ClientError, "Sandbox directory has not yet " \
|
177
181
|
"been created. Please run #{self.class}#create_sandox before " \
|
178
182
|
"trying to access the path."
|
179
|
-
end
|
180
183
|
end
|
181
184
|
|
182
185
|
# Deletes the sandbox path. Without calling this method, the sandbox path
|
@@ -21,6 +21,7 @@ require "rbconfig" unless defined?(RbConfig)
|
|
21
21
|
require_relative "../../errors"
|
22
22
|
require_relative "../../logging"
|
23
23
|
require_relative "../../shell_out"
|
24
|
+
require_relative "../../which"
|
24
25
|
|
25
26
|
module Kitchen
|
26
27
|
module Provisioner
|
@@ -31,6 +32,7 @@ module Kitchen
|
|
31
32
|
class Policyfile
|
32
33
|
include Logging
|
33
34
|
include ShellOut
|
35
|
+
include Which
|
34
36
|
|
35
37
|
# Creates a new cookbook resolver.
|
36
38
|
#
|
@@ -40,9 +42,9 @@ module Kitchen
|
|
40
42
|
# @param logger [Kitchen::Logger] a logger to use for output, defaults
|
41
43
|
# to `Kitchen.logger`
|
42
44
|
def initialize(policyfile, path, logger: Kitchen.logger, always_update: false)
|
43
|
-
@policyfile
|
44
|
-
@path
|
45
|
-
@logger
|
45
|
+
@policyfile = policyfile
|
46
|
+
@path = path
|
47
|
+
@logger = logger
|
46
48
|
@always_update = always_update
|
47
49
|
end
|
48
50
|
|
@@ -51,30 +53,29 @@ module Kitchen
|
|
51
53
|
# @param logger [Kitchen::Logger] a logger to use for output, defaults
|
52
54
|
# to `Kitchen.logger`
|
53
55
|
def self.load!(logger: Kitchen.logger)
|
54
|
-
|
56
|
+
# intentionally left blank
|
55
57
|
end
|
56
58
|
|
57
59
|
# Performs the cookbook resolution and vendors the resulting cookbooks
|
58
60
|
# in the desired path.
|
59
61
|
def resolve
|
60
|
-
info("Exporting cookbook dependencies from Policyfile #{path}
|
61
|
-
run_command("
|
62
|
+
info("Exporting cookbook dependencies from Policyfile #{path} using `#{cli_path} export`...")
|
63
|
+
run_command("#{cli_path} export #{escape_path(policyfile)} #{escape_path(path)} --force")
|
62
64
|
end
|
63
65
|
|
64
66
|
# Runs `chef install` to determine the correct cookbook set and
|
65
67
|
# generate the policyfile lock.
|
66
68
|
def compile
|
67
69
|
if File.exist?(lockfile)
|
68
|
-
info("Installing cookbooks for Policyfile #{policyfile} using
|
70
|
+
info("Installing cookbooks for Policyfile #{policyfile} using `#{cli_path} install`")
|
69
71
|
else
|
70
|
-
info("Policy lock file doesn't exist, running
|
71
|
-
"Policyfile #{policyfile}...")
|
72
|
+
info("Policy lock file doesn't exist, running `#{cli_path} install` for Policyfile #{policyfile}...")
|
72
73
|
end
|
73
|
-
run_command("
|
74
|
+
run_command("#{cli_path} install #{escape_path(policyfile)}")
|
74
75
|
|
75
76
|
if always_update
|
76
|
-
info("Updating policy lock using
|
77
|
-
run_command("
|
77
|
+
info("Updating policy lock using `#{cli_path} update`")
|
78
|
+
run_command("#{cli_path} update #{escape_path(policyfile)}")
|
78
79
|
end
|
79
80
|
end
|
80
81
|
|
@@ -126,33 +127,24 @@ module Kitchen
|
|
126
127
|
end
|
127
128
|
end
|
128
129
|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
end
|
148
|
-
logger.fatal("The `chef` executable cannot be found in your " \
|
149
|
-
"PATH. Ensure you have installed Chef Workstation " \
|
150
|
-
"from https://downloads.chef.io and that your PATH " \
|
151
|
-
"setting includes the path to the `chef` command.")
|
152
|
-
raise UserError,
|
153
|
-
"Could not find the chef executable in your PATH."
|
154
|
-
end
|
155
|
-
end
|
130
|
+
# Find the `chef` or `chef-cli` commands in the path or raise `chef` is present in
|
131
|
+
# ChefDK / Workstation releases, but is no longer shipped in any gems now that we
|
132
|
+
# use a Go based wrapper for the `chef` command in Workstation. The Ruby CLI has been
|
133
|
+
# renamed `chef-cli` under the hood and is shipped in the `chef-cli` gem.
|
134
|
+
#
|
135
|
+
# @api private
|
136
|
+
# @returns [String]
|
137
|
+
def cli_path
|
138
|
+
@cli_path ||= which("chef-cli") || which("chef") || no_cli_found_error
|
139
|
+
end
|
140
|
+
|
141
|
+
# @api private
|
142
|
+
def no_cli_found_error
|
143
|
+
@logger.fatal("The `chef` or `chef-cli` executables cannot be found in your " \
|
144
|
+
"PATH. Ensure you have installed Chef Workstation " \
|
145
|
+
"from https://downloads.chef.io and that your PATH " \
|
146
|
+
"setting includes the path to the `chef` or `chef-cli` commands.")
|
147
|
+
raise UserError, "Could not find the chef or chef-cli executables in your PATH."
|
156
148
|
end
|
157
149
|
|
158
150
|
end
|
@@ -70,6 +70,7 @@ module Kitchen
|
|
70
70
|
json = remote_path_join(config[:root_path], "dna.json")
|
71
71
|
args << "--json-attributes #{json}"
|
72
72
|
end
|
73
|
+
|
73
74
|
args << "--logfile #{config[:log_file]}" if config[:log_file]
|
74
75
|
|
75
76
|
# these flags are chef-client local mode only and will not work
|
@@ -77,10 +78,20 @@ module Kitchen
|
|
77
78
|
if config[:chef_zero_host]
|
78
79
|
args << "--chef-zero-host #{config[:chef_zero_host]}"
|
79
80
|
end
|
81
|
+
|
80
82
|
if config[:chef_zero_port]
|
81
83
|
args << "--chef-zero-port #{config[:chef_zero_port]}"
|
82
84
|
end
|
85
|
+
|
83
86
|
args << "--profile-ruby" if config[:profile_ruby]
|
87
|
+
|
88
|
+
if config[:slow_resource_report]
|
89
|
+
if config[:slow_resource_report].is_a?(Integer)
|
90
|
+
args << "--slow-report #{config[:slow_resource_report]}"
|
91
|
+
else
|
92
|
+
args << "--slow-report"
|
93
|
+
end
|
94
|
+
end
|
84
95
|
end
|
85
96
|
# rubocop:enable Metrics/CyclomaticComplexity
|
86
97
|
|
@@ -195,18 +195,16 @@ module Kitchen
|
|
195
195
|
FileUtils.mkdir_p(File.dirname(local))
|
196
196
|
|
197
197
|
Array(remotes).each do |file|
|
198
|
+
logger.debug("Attempting to download '#{file}' as file")
|
199
|
+
session.scp.download!(file, local)
|
200
|
+
rescue Net::SCP::Error
|
198
201
|
begin
|
199
|
-
logger.debug("Attempting to download '#{file}' as
|
200
|
-
session.scp.download!(file, local)
|
202
|
+
logger.debug("Attempting to download '#{file}' as directory")
|
203
|
+
session.scp.download!(file, local, recursive: true)
|
201
204
|
rescue Net::SCP::Error
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
rescue Net::SCP::Error
|
206
|
-
logger.warn(
|
207
|
-
"SCP download failed for file or directory '#{file}', perhaps it does not exist?"
|
208
|
-
)
|
209
|
-
end
|
205
|
+
logger.warn(
|
206
|
+
"SCP download failed for file or directory '#{file}', perhaps it does not exist?"
|
207
|
+
)
|
210
208
|
end
|
211
209
|
end
|
212
210
|
rescue Net::SSH::Exception => ex
|
@@ -365,11 +365,9 @@ module Kitchen
|
|
365
365
|
# @return [Winrm::Shells::Elevated] the elevated shell
|
366
366
|
# @api private
|
367
367
|
def elevated_session(retry_options = {})
|
368
|
-
@elevated_session ||=
|
369
|
-
|
370
|
-
|
371
|
-
shell.password = options[:elevated_password]
|
372
|
-
end
|
368
|
+
@elevated_session ||= connection(retry_options).shell(:elevated).tap do |shell|
|
369
|
+
shell.username = options[:elevated_username]
|
370
|
+
shell.password = options[:elevated_password]
|
373
371
|
end
|
374
372
|
end
|
375
373
|
|
@@ -169,11 +169,9 @@ module Kitchen
|
|
169
169
|
# @raise [ClientError] if the sandbox directory has no yet been created
|
170
170
|
# by calling `#create_sandbox`
|
171
171
|
def sandbox_path
|
172
|
-
@sandbox_path ||=
|
173
|
-
raise ClientError, "Sandbox directory has not yet " \
|
172
|
+
@sandbox_path ||= raise ClientError, "Sandbox directory has not yet " \
|
174
173
|
"been created. Please run #{self.class}#create_sandox before " \
|
175
174
|
"trying to access the path."
|
176
|
-
end
|
177
175
|
end
|
178
176
|
|
179
177
|
# Sets the API version for this verifier. If the verifier does not set
|
@@ -88,6 +88,7 @@ module Kitchen
|
|
88
88
|
env_state[:environment]["KITCHEN_INSTANCE"] = instance.name
|
89
89
|
env_state[:environment]["KITCHEN_PLATFORM"] = instance.platform.name
|
90
90
|
env_state[:environment]["KITCHEN_SUITE"] = instance.suite.name
|
91
|
+
env_state[:environment]["KITCHEN_USERNAME"] = instance.transport[:username] if instance.respond_to?(:transport)
|
91
92
|
state.each_pair do |key, value|
|
92
93
|
env_state[:environment]["KITCHEN_" + key.to_s.upcase] = value.to_s
|
93
94
|
end
|
data/lib/kitchen/version.rb
CHANGED
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
#
|
3
|
+
# Copyright:: Copyright (c) Chef Software Inc.
|
4
|
+
# License:: Apache License, Version 2.0
|
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
|
+
require "chef-utils/dsl/which" unless defined?(ChefUtils::DSL::Which)
|
19
|
+
require_relative "chef_utils_wiring" unless defined?(Kitchen::ChefUtilsWiring)
|
20
|
+
|
21
|
+
module Kitchen
|
22
|
+
module Which
|
23
|
+
include ChefUtils::DSL::Which
|
24
|
+
include ChefUtilsWiring
|
25
|
+
end
|
26
|
+
end
|
data/test-kitchen.gemspec
CHANGED
@@ -20,7 +20,7 @@ Gem::Specification.new do |gem|
|
|
20
20
|
gem.executables = %w{kitchen}
|
21
21
|
gem.require_paths = ["lib"]
|
22
22
|
|
23
|
-
gem.required_ruby_version = ">= 2.
|
23
|
+
gem.required_ruby_version = ">= 2.5"
|
24
24
|
|
25
25
|
gem.add_dependency "mixlib-shellout", ">= 1.2", "< 4.0"
|
26
26
|
gem.add_dependency "net-scp", ">= 1.1", "< 4.0" # pinning until we can confirm 4+ works
|
@@ -33,6 +33,7 @@ Gem::Specification.new do |gem|
|
|
33
33
|
gem.add_dependency "winrm", "~> 2.0"
|
34
34
|
gem.add_dependency "winrm-elevated", "~> 1.0"
|
35
35
|
gem.add_dependency "winrm-fs", "~> 1.1"
|
36
|
+
gem.add_dependency "chef-utils", ">= 16.4.35"
|
36
37
|
# Required to run the Chef provisioner local license check for remote systems
|
37
38
|
# TK is not under Chef EULA
|
38
39
|
gem.add_dependency "license-acceptance", ">= 1.0.11", "< 3.0" # pinning until we can confirm 3+ works
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: test-kitchen
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.12.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: 2021-06-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: mixlib-shellout
|
@@ -194,6 +194,20 @@ dependencies:
|
|
194
194
|
- - "~>"
|
195
195
|
- !ruby/object:Gem::Version
|
196
196
|
version: '1.1'
|
197
|
+
- !ruby/object:Gem::Dependency
|
198
|
+
name: chef-utils
|
199
|
+
requirement: !ruby/object:Gem::Requirement
|
200
|
+
requirements:
|
201
|
+
- - ">="
|
202
|
+
- !ruby/object:Gem::Version
|
203
|
+
version: 16.4.35
|
204
|
+
type: :runtime
|
205
|
+
prerelease: false
|
206
|
+
version_requirements: !ruby/object:Gem::Requirement
|
207
|
+
requirements:
|
208
|
+
- - ">="
|
209
|
+
- !ruby/object:Gem::Version
|
210
|
+
version: 16.4.35
|
197
211
|
- !ruby/object:Gem::Dependency
|
198
212
|
name: license-acceptance
|
199
213
|
requirement: !ruby/object:Gem::Requirement
|
@@ -387,6 +401,7 @@ files:
|
|
387
401
|
- bin/kitchen
|
388
402
|
- lib/kitchen.rb
|
389
403
|
- lib/kitchen/base64_stream.rb
|
404
|
+
- lib/kitchen/chef_utils_wiring.rb
|
390
405
|
- lib/kitchen/cli.rb
|
391
406
|
- lib/kitchen/collection.rb
|
392
407
|
- lib/kitchen/color.rb
|
@@ -415,6 +430,9 @@ files:
|
|
415
430
|
- lib/kitchen/generator/init.rb
|
416
431
|
- lib/kitchen/instance.rb
|
417
432
|
- lib/kitchen/lazy_hash.rb
|
433
|
+
- lib/kitchen/lifecycle_hook/base.rb
|
434
|
+
- lib/kitchen/lifecycle_hook/local.rb
|
435
|
+
- lib/kitchen/lifecycle_hook/remote.rb
|
418
436
|
- lib/kitchen/lifecycle_hooks.rb
|
419
437
|
- lib/kitchen/loader/yaml.rb
|
420
438
|
- lib/kitchen/logger.rb
|
@@ -454,6 +472,7 @@ files:
|
|
454
472
|
- lib/kitchen/verifier/dummy.rb
|
455
473
|
- lib/kitchen/verifier/shell.rb
|
456
474
|
- lib/kitchen/version.rb
|
475
|
+
- lib/kitchen/which.rb
|
457
476
|
- lib/vendor/hash_recursive_merge.rb
|
458
477
|
- support/busser_install_command.ps1
|
459
478
|
- support/busser_install_command.sh
|
@@ -493,14 +512,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
493
512
|
requirements:
|
494
513
|
- - ">="
|
495
514
|
- !ruby/object:Gem::Version
|
496
|
-
version: '2.
|
515
|
+
version: '2.5'
|
497
516
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
498
517
|
requirements:
|
499
518
|
- - ">="
|
500
519
|
- !ruby/object:Gem::Version
|
501
520
|
version: '0'
|
502
521
|
requirements: []
|
503
|
-
rubygems_version: 3.
|
522
|
+
rubygems_version: 3.2.15
|
504
523
|
signing_key:
|
505
524
|
specification_version: 4
|
506
525
|
summary: Test Kitchen is an integration tool for developing and testing infrastructure
|