knife 17.3.48 → 17.5.22
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +2 -2
- data/knife.gemspec +3 -3
- data/lib/chef/knife/bootstrap/train_connector.rb +3 -3
- data/lib/chef/knife/bootstrap.rb +3 -0
- data/lib/chef/knife/client_create.rb +39 -0
- data/lib/chef/knife/cookbook_upload.rb +34 -13
- data/lib/chef/knife/core/windows_bootstrap_context.rb +2 -2
- data/lib/chef/knife/version.rb +1 -1
- data/spec/data/knife/temp_dir/tmp.pem +0 -0
- data/spec/unit/knife/bootstrap_spec.rb +14 -1
- data/spec/unit/knife/client_create_spec.rb +65 -2
- data/spec/unit/knife/cookbook_upload_spec.rb +98 -36
- data/spec/unit/knife/core/windows_bootstrap_context_spec.rb +1 -1
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f3876674845d37200a33f647539c9dc36e5b0026dab8454f19862dd41f7bf7a7
|
4
|
+
data.tar.gz: 63774f4ec6bfa541eb7fd2f4d66a5a810a6793c23cb9cd631b6281680f2ec31e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 61aa15c7383aa1a5b128c5d0a963ba503280809437792cb1511fbe64de1fd954a683f02afe5ff0241618c9a74dfe46eccb74dc8b16bfb87b84ad3e376351178d
|
7
|
+
data.tar.gz: ae28adfb4b759bd6edbecb131f415b2aa35dd7019eb59652bd6a4dba1796801009bd99195837c1d5f5993d408d69c930c0ef0384a2f8f0c8ee982e9e631089c9
|
data/Gemfile
CHANGED
@@ -17,10 +17,10 @@ group(:omnibus_package, :pry) do
|
|
17
17
|
end
|
18
18
|
|
19
19
|
group(:chefstyle) do
|
20
|
-
gem "chefstyle", git: "https://github.com/chef/chefstyle.git", branch: "
|
20
|
+
gem "chefstyle", git: "https://github.com/chef/chefstyle.git", branch: "main"
|
21
21
|
end
|
22
22
|
|
23
|
-
gem "ohai", git: "https://github.com/chef/ohai.git", branch: "
|
23
|
+
gem "ohai", git: "https://github.com/chef/ohai.git", branch: "main"
|
24
24
|
gem "chef", path: ".."
|
25
25
|
gem "chef-utils", path: File.expand_path("../chef-utils", __dir__) if File.exist?(File.expand_path("../chef-utils", __dir__))
|
26
26
|
gem "chef-config", path: File.expand_path("../chef-config", __dir__) if File.exist?(File.expand_path("../chef-config", __dir__))
|
data/knife.gemspec
CHANGED
@@ -30,8 +30,8 @@ Gem::Specification.new do |s|
|
|
30
30
|
s.add_dependency "net-ssh-multi", "~> 1.2", ">= 1.2.1"
|
31
31
|
s.add_dependency "ed25519", "~> 1.2" # ed25519 ssh key support
|
32
32
|
s.add_dependency "bcrypt_pbkdf", "~> 1.1" # ed25519 ssh key support
|
33
|
-
#
|
34
|
-
# s.add_dependency "x25519" # ed25519 KEX module
|
33
|
+
# disabling this until we get get it to compile on RHEL 7
|
34
|
+
# s.add_dependency "x25519", ">= 1.0.9" # ed25519 KEX module. 1.0.9+ required to resolve sigill failures
|
35
35
|
s.add_dependency "highline", ">= 1.6.9", "< 3" # Used in UI to present a list, no other usage.
|
36
36
|
|
37
37
|
s.add_dependency "tty-prompt", "~> 0.21" # knife ui.ask prompt
|
@@ -52,7 +52,7 @@ Gem::Specification.new do |s|
|
|
52
52
|
|
53
53
|
s.metadata = {
|
54
54
|
"bug_tracker_uri" => "https://github.com/chef/chef/issues",
|
55
|
-
"changelog_uri" => "https://github.com/chef/chef/blob/
|
55
|
+
"changelog_uri" => "https://github.com/chef/chef/blob/main/CHANGELOG.md",
|
56
56
|
"documentation_uri" => "https://docs.chef.io/",
|
57
57
|
"homepage_uri" => "https://www.chef.io",
|
58
58
|
"mailing_list_uri" => "https://discourse.chef.io/",
|
@@ -240,7 +240,7 @@ class Chef
|
|
240
240
|
|
241
241
|
# Now that everything is populated, fill in anything missing
|
242
242
|
# that may be found in user ssh config
|
243
|
-
opts.merge!(missing_opts_from_ssh_config(opts
|
243
|
+
opts.merge!(missing_opts_from_ssh_config(opts))
|
244
244
|
|
245
245
|
Train.target_config(opts)
|
246
246
|
end
|
@@ -297,12 +297,12 @@ class Chef
|
|
297
297
|
# in the configuration passed in.
|
298
298
|
# This is necessary because train will default these values
|
299
299
|
# itself - causing SSH config data to be ignored
|
300
|
-
def missing_opts_from_ssh_config(config
|
300
|
+
def missing_opts_from_ssh_config(config)
|
301
301
|
return {} unless config[:backend] == "ssh"
|
302
302
|
|
303
303
|
host_cfg = ssh_config_for_host(config[:host])
|
304
304
|
opts_out = {}
|
305
|
-
|
305
|
+
host_cfg.each do |key, _value|
|
306
306
|
if SSH_CONFIG_OVERRIDE_KEYS.include?(key) && !config.key?(key)
|
307
307
|
opts_out[key] = host_cfg[key]
|
308
308
|
end
|
data/lib/chef/knife/bootstrap.rb
CHANGED
@@ -20,6 +20,7 @@ require_relative "../knife"
|
|
20
20
|
require_relative "data_bag_secret_options"
|
21
21
|
require "chef-utils/dist" unless defined?(ChefUtils::Dist)
|
22
22
|
require "license_acceptance/cli_flags/mixlib_cli"
|
23
|
+
|
23
24
|
module LicenseAcceptance
|
24
25
|
autoload :Acceptor, "license_acceptance/acceptor"
|
25
26
|
end
|
@@ -705,6 +706,8 @@ class Chef
|
|
705
706
|
ui.warn("#{e.message} - trying with pty request")
|
706
707
|
conn_options[:pty] = true # ensure we can talk to systems with requiretty set true in sshd config
|
707
708
|
retry
|
709
|
+
elsif e.reason == :sudo_missing_terminal
|
710
|
+
ui.error "Sudo password is required for this operation. Please enter password using -P or --ssh-password option"
|
708
711
|
elsif config[:use_sudo_password] && (e.reason == :sudo_password_required || e.reason == :bad_sudo_password) && limit < 3
|
709
712
|
ui.warn("Failed to authenticate #{conn_options[:user]} to #{server_name} - #{e.message} \n sudo: #{limit} incorrect password attempt")
|
710
713
|
sudo_password = ui.ask("Enter sudo password for #{conn_options[:user]}@#{server_name}:", echo: false)
|
@@ -54,6 +54,10 @@ class Chef
|
|
54
54
|
@client_field ||= Chef::ApiClientV1.new
|
55
55
|
end
|
56
56
|
|
57
|
+
def file
|
58
|
+
config[:file]
|
59
|
+
end
|
60
|
+
|
57
61
|
def create_client(client)
|
58
62
|
# should not be using save :( bad behavior
|
59
63
|
Chef::ApiClientV1.from_hash(client).save
|
@@ -81,6 +85,8 @@ class Chef
|
|
81
85
|
client.public_key File.read(File.expand_path(config[:public_key]))
|
82
86
|
end
|
83
87
|
|
88
|
+
file_is_writable!
|
89
|
+
|
84
90
|
output = edit_hash(client)
|
85
91
|
final_client = create_client(output)
|
86
92
|
ui.info("Created #{final_client}")
|
@@ -96,6 +102,39 @@ class Chef
|
|
96
102
|
end
|
97
103
|
end
|
98
104
|
end
|
105
|
+
|
106
|
+
#
|
107
|
+
# This method is used to verify that the file and it's containing
|
108
|
+
# directory are writable. This ensures that you don't create the client
|
109
|
+
# and then lose the private key because you weren't able to write it to
|
110
|
+
# disk.
|
111
|
+
#
|
112
|
+
# @return [void]
|
113
|
+
#
|
114
|
+
def file_is_writable!
|
115
|
+
return unless file
|
116
|
+
|
117
|
+
dir = File.dirname(File.expand_path(file))
|
118
|
+
unless File.exist?(dir)
|
119
|
+
ui.fatal "Directory #{dir} does not exist. Please create and retry."
|
120
|
+
exit 1
|
121
|
+
end
|
122
|
+
|
123
|
+
unless File.directory?(dir)
|
124
|
+
ui.fatal "#{dir} exists, but is not a directory. Please update your file path (--file #{file}) or re-create #{dir} as a directory."
|
125
|
+
exit 1
|
126
|
+
end
|
127
|
+
|
128
|
+
unless File.writable?(dir)
|
129
|
+
ui.fatal "Directory #{dir} is not writable. Please check the permissions."
|
130
|
+
exit 1
|
131
|
+
end
|
132
|
+
|
133
|
+
if File.exist?(file) && !File.writable?(file)
|
134
|
+
ui.fatal "File #{file} is not writable. Please check the permissions."
|
135
|
+
exit 1
|
136
|
+
end
|
137
|
+
end
|
99
138
|
end
|
100
139
|
end
|
101
140
|
end
|
@@ -71,6 +71,11 @@ class Chef
|
|
71
71
|
long: "--include-dependencies",
|
72
72
|
description: "Also upload cookbook dependencies."
|
73
73
|
|
74
|
+
option :check_dependencies,
|
75
|
+
boolean: true, long: "--[no-]check-dependencies",
|
76
|
+
description: "Whether or not cookbook dependencies are verified before uploading cookbook(s) to #{ChefUtils::Dist::Server::PRODUCT}. You shouldn't disable this unless you really know what you're doing.",
|
77
|
+
default: true
|
78
|
+
|
74
79
|
def run
|
75
80
|
# Sanity check before we load anything from the server
|
76
81
|
if ! config[:all] && @name_args.empty?
|
@@ -86,11 +91,6 @@ class Chef
|
|
86
91
|
upload_failures = 0
|
87
92
|
upload_ok = 0
|
88
93
|
|
89
|
-
# Get a list of cookbooks and their versions from the server
|
90
|
-
# to check for the existence of a cookbook's dependencies.
|
91
|
-
@server_side_cookbooks = Chef::CookbookVersion.list_all_versions
|
92
|
-
justify_width = @server_side_cookbooks.map(&:size).max.to_i + 2
|
93
|
-
|
94
94
|
cookbooks = []
|
95
95
|
cookbooks_to_upload.each do |cookbook_name, cookbook|
|
96
96
|
raise Chef::Exceptions::MetadataNotFound.new(cookbook.root_paths[0], cookbook_name) unless cookbook.has_metadata_file?
|
@@ -120,7 +120,7 @@ class Chef
|
|
120
120
|
if config[:all]
|
121
121
|
if cookbooks_for_upload.any?
|
122
122
|
begin
|
123
|
-
upload(cookbooks_for_upload
|
123
|
+
upload(cookbooks_for_upload)
|
124
124
|
rescue Chef::Exceptions::CookbookFrozen
|
125
125
|
ui.warn("Not updating version constraints for some cookbooks in the environment as the cookbook is frozen.")
|
126
126
|
ui.error("Uploading of some of the cookbooks must be failed. Remove cookbook whose version is frozen from your cookbooks repo OR use --force option.")
|
@@ -133,7 +133,7 @@ class Chef
|
|
133
133
|
else
|
134
134
|
tmp_cl.each do |cookbook_name, cookbook|
|
135
135
|
|
136
|
-
upload([cookbook]
|
136
|
+
upload([cookbook])
|
137
137
|
upload_ok += 1
|
138
138
|
rescue Exceptions::CookbookNotFoundInRepo => e
|
139
139
|
upload_failures += 1
|
@@ -165,6 +165,27 @@ class Chef
|
|
165
165
|
end
|
166
166
|
end
|
167
167
|
|
168
|
+
def server_side_cookbooks
|
169
|
+
@server_side_cookbooks ||= Chef::CookbookVersion.list_all_versions
|
170
|
+
end
|
171
|
+
|
172
|
+
def justify_width
|
173
|
+
@justify_width ||= server_side_cookbooks.map(&:size).max.to_i + 2
|
174
|
+
end
|
175
|
+
|
176
|
+
#
|
177
|
+
# @param cookbook [Chef::CookbookVersion]
|
178
|
+
#
|
179
|
+
def left_justify_name(cookbook)
|
180
|
+
# We only want to lookup justify width value if we're already loading
|
181
|
+
# cookbooks to check dependencies exist in Chef Infra Server.
|
182
|
+
if config[:check_dependencies] == true
|
183
|
+
cookbook.name.to_s.ljust(justify_width + 10)
|
184
|
+
else
|
185
|
+
cookbook.name.to_s.ljust(24)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
168
189
|
def cookbooks_to_upload
|
169
190
|
@cookbooks_to_upload ||=
|
170
191
|
if config[:all]
|
@@ -220,11 +241,11 @@ class Chef
|
|
220
241
|
end
|
221
242
|
end
|
222
243
|
|
223
|
-
def upload(cookbooks
|
244
|
+
def upload(cookbooks)
|
224
245
|
cookbooks.each do |cb|
|
225
|
-
ui.info("Uploading #{cb
|
246
|
+
ui.info("Uploading #{left_justify_name(cb)} [#{cb.version}]")
|
226
247
|
check_for_broken_links!(cb)
|
227
|
-
check_for_dependencies!(cb)
|
248
|
+
check_for_dependencies!(cb) if config[:check_dependencies] == true
|
228
249
|
end
|
229
250
|
Chef::CookbookUploader.new(cookbooks, force: config[:force], concurrency: config[:concurrency]).upload_cookbooks
|
230
251
|
rescue Chef::Exceptions::CookbookFrozen => e
|
@@ -265,12 +286,12 @@ class Chef
|
|
265
286
|
end
|
266
287
|
|
267
288
|
def check_server_side_cookbooks(cookbook_name, version)
|
268
|
-
if
|
289
|
+
if server_side_cookbooks[cookbook_name].nil?
|
269
290
|
false
|
270
291
|
else
|
271
|
-
versions =
|
292
|
+
versions = server_side_cookbooks[cookbook_name]["versions"].collect { |versions| versions["version"] }
|
272
293
|
Log.debug "Versions of cookbook '#{cookbook_name}' returned by the server: #{versions.join(", ")}"
|
273
|
-
|
294
|
+
server_side_cookbooks[cookbook_name]["versions"].each do |versions_hash|
|
274
295
|
if Chef::VersionConstraint.new(version).include?(versions_hash["version"])
|
275
296
|
Log.debug "Matched cookbook '#{cookbook_name}' with constraint '#{version}' to cookbook version '#{versions_hash["version"]}' on the server"
|
276
297
|
return true
|
@@ -86,8 +86,8 @@ class Chef
|
|
86
86
|
client_rb << "# Using default node name (fqdn)\n"
|
87
87
|
end
|
88
88
|
|
89
|
-
if
|
90
|
-
client_rb << %Q{log_level :#{
|
89
|
+
if chef_config[:config_log_level]
|
90
|
+
client_rb << %Q{log_level :#{chef_config[:config_log_level]}\n}
|
91
91
|
else
|
92
92
|
client_rb << "log_level :auto\n"
|
93
93
|
end
|
data/lib/chef/knife/version.rb
CHANGED
File without changes
|
@@ -1307,7 +1307,7 @@ describe Chef::Knife::Bootstrap do
|
|
1307
1307
|
context "when no identity file is specified" do
|
1308
1308
|
it "generates the expected configuration (no keys, keys_only false)" do
|
1309
1309
|
expect(knife.ssh_identity_opts).to eq( {
|
1310
|
-
key_files: [
|
1310
|
+
key_files: [],
|
1311
1311
|
keys_only: false,
|
1312
1312
|
})
|
1313
1313
|
end
|
@@ -2050,6 +2050,19 @@ describe Chef::Knife::Bootstrap do
|
|
2050
2050
|
expect { knife.do_connect({}) }.to raise_error(expected_error)
|
2051
2051
|
end
|
2052
2052
|
end
|
2053
|
+
|
2054
|
+
context "when a train sudo error is thrown for missing terminal" do
|
2055
|
+
let(:ui_error_msg) { "Sudo password is required for this operation. Please enter password using -P or --ssh-password option" }
|
2056
|
+
let(:expected_error) { Train::UserError.new(ui_error_msg, :sudo_missing_terminal) }
|
2057
|
+
before do
|
2058
|
+
allow(connection).to receive(:connect!).and_raise(expected_error)
|
2059
|
+
end
|
2060
|
+
it "outputs user friendly error message" do
|
2061
|
+
expect { knife.do_connect({}) }.not_to raise_error
|
2062
|
+
expect(stderr.string).to include(ui_error_msg)
|
2063
|
+
end
|
2064
|
+
end
|
2065
|
+
|
2053
2066
|
end
|
2054
2067
|
|
2055
2068
|
describe "validate_winrm_transport_opts!" do
|
@@ -54,6 +54,19 @@ describe Chef::Knife::ClientCreate do
|
|
54
54
|
Chef::Config[:node_name] = "webmonkey.example.com"
|
55
55
|
end
|
56
56
|
|
57
|
+
let(:tmpdir) { Dir.mktmpdir }
|
58
|
+
let(:file_path) { File.join(tmpdir, "client.pem") }
|
59
|
+
let(:dir_path) { File.dirname(file_path) }
|
60
|
+
|
61
|
+
before do
|
62
|
+
allow(File).to receive(:exist?).and_call_original
|
63
|
+
allow(File).to receive(:exist?).with(file_path).and_return(false)
|
64
|
+
allow(File).to receive(:exist?).with(dir_path).and_return(true)
|
65
|
+
allow(File).to receive(:directory?).with(dir_path).and_return(true)
|
66
|
+
allow(File).to receive(:writable?).with(file_path).and_return(true)
|
67
|
+
allow(File).to receive(:writable?).with(dir_path).and_return(true)
|
68
|
+
end
|
69
|
+
|
57
70
|
describe "run" do
|
58
71
|
context "when nothing is passed" do
|
59
72
|
# from spec/support/shared/unit/knife_shared.rb
|
@@ -118,16 +131,66 @@ describe Chef::Knife::ClientCreate do
|
|
118
131
|
|
119
132
|
describe "with -f or --file" do
|
120
133
|
before do
|
134
|
+
knife.config[:file] = file_path
|
121
135
|
client.private_key "woot"
|
122
136
|
end
|
123
137
|
|
124
138
|
it "should write the private key to a file" do
|
125
|
-
knife.config[:file] = "/tmp/monkeypants"
|
126
139
|
filehandle = double("Filehandle")
|
127
140
|
expect(filehandle).to receive(:print).with("woot")
|
128
|
-
expect(File).to receive(:open).with(
|
141
|
+
expect(File).to receive(:open).with(file_path, "w").and_yield(filehandle)
|
129
142
|
knife.run
|
130
143
|
end
|
144
|
+
|
145
|
+
context "when the directory does not exist" do
|
146
|
+
before { allow(File).to receive(:exist?).with(dir_path).and_return(false) }
|
147
|
+
|
148
|
+
it "writes a fatal message and exits 1" do
|
149
|
+
expect(knife.ui).to receive(:fatal).with("Directory #{dir_path} does not exist. Please create and retry.")
|
150
|
+
expect { knife.run }.to raise_error(SystemExit)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
context "when the directory is not writable" do
|
155
|
+
before { allow(File).to receive(:writable?).with(dir_path).and_return(false) }
|
156
|
+
|
157
|
+
it "writes a fatal message and exits 1" do
|
158
|
+
expect(knife.ui).to receive(:fatal).with("Directory #{dir_path} is not writable. Please check the permissions.")
|
159
|
+
expect { knife.run }.to raise_error(SystemExit)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
context "when the directory is a file" do
|
164
|
+
before { allow(File).to receive(:directory?).with(dir_path).and_return(false) }
|
165
|
+
|
166
|
+
it "writes a fatal message and exits 1" do
|
167
|
+
expect(knife.ui).to receive(:fatal).with("#{dir_path} exists, but is not a directory. Please update your file path (--file #{file_path}) or re-create #{dir_path} as a directory.")
|
168
|
+
expect { knife.run }.to raise_error(SystemExit)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
context "when the file does not exist" do
|
173
|
+
before do
|
174
|
+
allow(File).to receive(:exist?).with(file_path).and_return(false)
|
175
|
+
end
|
176
|
+
|
177
|
+
it "does not log a fatal message and does not raise exception" do
|
178
|
+
expect(knife.ui).not_to receive(:fatal)
|
179
|
+
expect { knife.run }.not_to raise_error
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
context "when the file exists and is not writable" do
|
184
|
+
before do
|
185
|
+
allow(File).to receive(:exist?).with(file_path).and_return(true)
|
186
|
+
allow(File).to receive(:writable?).with(file_path).and_return(false)
|
187
|
+
end
|
188
|
+
|
189
|
+
it "writes a fatal message and exits 1" do
|
190
|
+
expect(knife.ui).to receive(:fatal).with("File #{file_path} is not writable. Please check the permissions.")
|
191
|
+
expect { knife.run }.to raise_error(SystemExit)
|
192
|
+
end
|
193
|
+
end
|
131
194
|
end
|
132
195
|
|
133
196
|
describe "with -p or --public-key" do
|
@@ -60,11 +60,12 @@ describe Chef::Knife::CookbookUpload do
|
|
60
60
|
before(:each) do
|
61
61
|
allow(Chef::CookbookLoader).to receive(:new).and_return(cookbook_loader)
|
62
62
|
allow(Chef::CookbookLoader).to receive(:copy_to_tmp_dir_from_array).and_yield(cookbook_loader)
|
63
|
+
allow(Chef::CookbookVersion).to receive(:list).and_return({})
|
64
|
+
allow(Chef::CookbookVersion).to receive(:list_all_versions).and_return({})
|
63
65
|
end
|
64
66
|
|
65
67
|
describe "with --concurrency" do
|
66
68
|
it "should upload cookbooks with predefined concurrency" do
|
67
|
-
allow(Chef::CookbookVersion).to receive(:list_all_versions).and_return({})
|
68
69
|
knife.config[:concurrency] = 3
|
69
70
|
test_cookbook = Chef::CookbookVersion.new("test_cookbook", "/tmp/blah")
|
70
71
|
allow(cookbook_loader).to receive(:each).and_yield("test_cookbook", test_cookbook)
|
@@ -79,7 +80,6 @@ describe Chef::Knife::CookbookUpload do
|
|
79
80
|
describe "run" do
|
80
81
|
before(:each) do
|
81
82
|
allow(Chef::CookbookUploader).to receive_messages(new: cookbook_uploader)
|
82
|
-
allow(Chef::CookbookVersion).to receive(:list_all_versions).and_return({})
|
83
83
|
end
|
84
84
|
|
85
85
|
it "should print usage and exit when a cookbook name is not provided" do
|
@@ -214,48 +214,110 @@ describe Chef::Knife::CookbookUpload do
|
|
214
214
|
end
|
215
215
|
end
|
216
216
|
|
217
|
-
|
218
|
-
|
217
|
+
context "when chef_dependencies config is disabled" do
|
218
|
+
before do
|
219
|
+
knife.config[:check_dependencies] = false
|
220
|
+
end
|
219
221
|
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
222
|
+
describe "when specifying a cookbook name with missing dependencies" do
|
223
|
+
let(:cookbook_dependency) { Chef::CookbookVersion.new("dependency", "/tmp/blah") }
|
224
|
+
|
225
|
+
before(:each) do
|
226
|
+
cookbook.metadata.depends("dependency")
|
227
|
+
allow(cookbook_loader).to receive(:[]) do |ckbk|
|
228
|
+
{ "test_cookbook" => cookbook,
|
229
|
+
"dependency" => cookbook_dependency }[ckbk]
|
230
|
+
end
|
231
|
+
allow(knife).to receive(:cookbook_names).and_return(%w{cookbook_dependency test_cookbook})
|
232
|
+
@stdout, @stderr, @stdin = StringIO.new, StringIO.new, StringIO.new
|
233
|
+
knife.ui = Chef::Knife::UI.new(@stdout, @stderr, @stdin, {})
|
225
234
|
end
|
226
|
-
allow(knife).to receive(:cookbook_names).and_return(%w{cookbook_dependency test_cookbook})
|
227
|
-
@stdout, @stderr, @stdin = StringIO.new, StringIO.new, StringIO.new
|
228
|
-
knife.ui = Chef::Knife::UI.new(@stdout, @stderr, @stdin, {})
|
229
|
-
end
|
230
235
|
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
236
|
+
it "should not fetch all cookbooks from Chef Infra Server" do
|
237
|
+
expect(Chef::CookbookVersion).not_to receive(:list_all_versions)
|
238
|
+
knife.run
|
239
|
+
end
|
240
|
+
|
241
|
+
it "should upload the cookbook" do
|
242
|
+
expect(cookbook_loader).to receive(:[]).once.with("test_cookbook")
|
243
|
+
expect(cookbook_uploader).to receive(:upload_cookbooks)
|
244
|
+
knife.run
|
245
|
+
end
|
246
|
+
|
247
|
+
it "should not output a message for a single missing dependency" do
|
248
|
+
knife.run
|
249
|
+
expect(@stderr.string).not_to include("Cookbook test_cookbook depends on cookbooks which are not currently")
|
250
|
+
expect(@stderr.string).not_to include("being uploaded and cannot be found on the server.")
|
251
|
+
expect(@stderr.string).not_to include("The missing cookbook(s) are: 'dependency' version '>= 0.0.0'")
|
252
|
+
end
|
253
|
+
|
254
|
+
it "should not output a message for a multiple missing dependencies which are concatenated" do
|
255
|
+
cookbook_dependency2 = Chef::CookbookVersion.new("dependency2")
|
256
|
+
cookbook.metadata.depends("dependency2")
|
257
|
+
allow(cookbook_loader).to receive(:[]) do |ckbk|
|
258
|
+
{ "test_cookbook" => cookbook,
|
259
|
+
"dependency" => cookbook_dependency,
|
260
|
+
"dependency2" => cookbook_dependency2 }[ckbk]
|
261
|
+
end
|
262
|
+
allow(knife).to receive(:cookbook_names).and_return(%w{dependency dependency2 test_cookbook})
|
263
|
+
knife.run
|
264
|
+
expect(@stderr.string).not_to include("Cookbook test_cookbook depends on cookbooks which are not currently")
|
265
|
+
expect(@stderr.string).not_to include("being uploaded and cannot be found on the server.")
|
266
|
+
expect(@stderr.string).not_to include("The missing cookbook(s) are:")
|
267
|
+
expect(@stderr.string).not_to include("'dependency' version '>= 0.0.0'")
|
268
|
+
expect(@stderr.string).not_to include("'dependency2' version '>= 0.0.0'")
|
269
|
+
end
|
235
270
|
end
|
271
|
+
end
|
236
272
|
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
expect(@stderr.string).to include("being uploaded and cannot be found on the server.")
|
241
|
-
expect(@stderr.string).to include("The missing cookbook(s) are: 'dependency' version '>= 0.0.0'")
|
273
|
+
context "when chef_dependencies config is enabled" do
|
274
|
+
before do
|
275
|
+
knife.config[:check_dependencies] = true
|
242
276
|
end
|
243
277
|
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
"
|
278
|
+
describe "when specifying a cookbook name with missing dependencies" do
|
279
|
+
let(:cookbook_dependency) { Chef::CookbookVersion.new("dependency", "/tmp/blah") }
|
280
|
+
|
281
|
+
before(:each) do
|
282
|
+
cookbook.metadata.depends("dependency")
|
283
|
+
allow(cookbook_loader).to receive(:[]) do |ckbk|
|
284
|
+
{ "test_cookbook" => cookbook,
|
285
|
+
"dependency" => cookbook_dependency }[ckbk]
|
286
|
+
end
|
287
|
+
allow(knife).to receive(:cookbook_names).and_return(%w{cookbook_dependency test_cookbook})
|
288
|
+
@stdout, @stderr, @stdin = StringIO.new, StringIO.new, StringIO.new
|
289
|
+
knife.ui = Chef::Knife::UI.new(@stdout, @stderr, @stdin, {})
|
290
|
+
end
|
291
|
+
|
292
|
+
it "should exit and not upload the cookbook" do
|
293
|
+
expect(cookbook_loader).to receive(:[]).once.with("test_cookbook")
|
294
|
+
expect(cookbook_uploader).not_to receive(:upload_cookbooks)
|
295
|
+
expect { knife.run }.to raise_error(SystemExit)
|
296
|
+
end
|
297
|
+
|
298
|
+
it "should output a message for a single missing dependency" do
|
299
|
+
expect { knife.run }.to raise_error(SystemExit)
|
300
|
+
expect(@stderr.string).to include("Cookbook test_cookbook depends on cookbooks which are not currently")
|
301
|
+
expect(@stderr.string).to include("being uploaded and cannot be found on the server.")
|
302
|
+
expect(@stderr.string).to include("The missing cookbook(s) are: 'dependency' version '>= 0.0.0'")
|
303
|
+
end
|
304
|
+
|
305
|
+
it "should output a message for a multiple missing dependencies which are concatenated" do
|
306
|
+
cookbook_dependency2 = Chef::CookbookVersion.new("dependency2")
|
307
|
+
cookbook.metadata.depends("dependency2")
|
308
|
+
allow(cookbook_loader).to receive(:[]) do |ckbk|
|
309
|
+
{ "test_cookbook" => cookbook,
|
310
|
+
"dependency" => cookbook_dependency,
|
311
|
+
"dependency2" => cookbook_dependency2 }[ckbk]
|
312
|
+
end
|
313
|
+
allow(knife).to receive(:cookbook_names).and_return(%w{dependency dependency2 test_cookbook})
|
314
|
+
expect { knife.run }.to raise_error(SystemExit)
|
315
|
+
expect(@stderr.string).to include("Cookbook test_cookbook depends on cookbooks which are not currently")
|
316
|
+
expect(@stderr.string).to include("being uploaded and cannot be found on the server.")
|
317
|
+
expect(@stderr.string).to include("The missing cookbook(s) are:")
|
318
|
+
expect(@stderr.string).to include("'dependency' version '>= 0.0.0'")
|
319
|
+
expect(@stderr.string).to include("'dependency2' version '>= 0.0.0'")
|
251
320
|
end
|
252
|
-
allow(knife).to receive(:cookbook_names).and_return(%w{dependency dependency2 test_cookbook})
|
253
|
-
expect { knife.run }.to raise_error(SystemExit)
|
254
|
-
expect(@stderr.string).to include("Cookbook test_cookbook depends on cookbooks which are not currently")
|
255
|
-
expect(@stderr.string).to include("being uploaded and cannot be found on the server.")
|
256
|
-
expect(@stderr.string).to include("The missing cookbook(s) are:")
|
257
|
-
expect(@stderr.string).to include("'dependency' version '>= 0.0.0'")
|
258
|
-
expect(@stderr.string).to include("'dependency2' version '>= 0.0.0'")
|
259
321
|
end
|
260
322
|
end
|
261
323
|
|
@@ -169,7 +169,7 @@ describe Chef::Knife::Core::WindowsBootstrapContext do
|
|
169
169
|
echo.file_backup_path "c:/chef/backup"
|
170
170
|
echo.cache_options ^({:path =^> "C:\\\\chef\\\\cache\\\\checksums", :skip_expires =^> true}^)
|
171
171
|
echo.# Using default node name ^(fqdn^)
|
172
|
-
echo.log_level
|
172
|
+
echo.log_level :info
|
173
173
|
echo.log_location STDOUT
|
174
174
|
EXPECTED
|
175
175
|
expect(bootstrap_context.config_content).to eq expected
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: knife
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 17.
|
4
|
+
version: 17.5.22
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Adam Jacob
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-09-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: chef-config
|
@@ -751,6 +751,7 @@ files:
|
|
751
751
|
- spec/data/kitchen/openldap/recipes/woot.rb
|
752
752
|
- spec/data/knife-home/.chef/plugins/knife/example_home_subcommand.rb
|
753
753
|
- spec/data/knife-site-subcommands/plugins/knife/example_subcommand.rb
|
754
|
+
- spec/data/knife/temp_dir/tmp.pem
|
754
755
|
- spec/data/knife_subcommand/test_explicit_category.rb
|
755
756
|
- spec/data/knife_subcommand/test_name_mapping.rb
|
756
757
|
- spec/data/knife_subcommand/test_yourself.rb
|
@@ -1129,7 +1130,7 @@ licenses:
|
|
1129
1130
|
- Apache-2.0
|
1130
1131
|
metadata:
|
1131
1132
|
bug_tracker_uri: https://github.com/chef/chef/issues
|
1132
|
-
changelog_uri: https://github.com/chef/chef/blob/
|
1133
|
+
changelog_uri: https://github.com/chef/chef/blob/main/CHANGELOG.md
|
1133
1134
|
documentation_uri: https://docs.chef.io/
|
1134
1135
|
homepage_uri: https://www.chef.io
|
1135
1136
|
mailing_list_uri: https://discourse.chef.io/
|