chef 18.4.12 → 18.6.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +9 -2
- data/chef-universal-mingw-ucrt.gemspec +1 -1
- data/chef.gemspec +8 -8
- data/lib/chef/client.rb +0 -15
- data/lib/chef/cookbook/chefignore.rb +4 -1
- data/lib/chef/cookbook/cookbook_version_loader.rb +1 -1
- data/lib/chef/cookbook/remote_file_vendor.rb +3 -2
- data/lib/chef/cookbook/synchronizer.rb +2 -1
- data/lib/chef/cookbook_manifest.rb +2 -2
- data/lib/chef/exceptions.rb +1 -1
- data/lib/chef/file_cache.rb +17 -2
- data/lib/chef/formatters/doc.rb +1 -1
- data/lib/chef/mixin/{homebrew_user.rb → homebrew.rb} +13 -16
- data/lib/chef/mixin/openssl_helper.rb +2 -13
- data/lib/chef/node/attribute.rb +3 -11
- data/lib/chef/node/immutable_collections.rb +15 -8
- data/lib/chef/node/mixin/state_tracking.rb +6 -3
- data/lib/chef/policy_builder/policyfile.rb +8 -0
- data/lib/chef/provider/package/chocolatey.rb +56 -26
- data/lib/chef/provider/package/homebrew.rb +6 -9
- data/lib/chef/provider/package/powershell.rb +1 -0
- data/lib/chef/provider/package/rubygems.rb +4 -0
- data/lib/chef/provider/package/snap.rb +1 -0
- data/lib/chef/provider/package/zypper.rb +0 -1
- data/lib/chef/provider/service/windows.rb +0 -1
- data/lib/chef/provider/user/windows.rb +5 -0
- data/lib/chef/resource/chef_client_config.rb +4 -2
- data/lib/chef/resource/chef_client_systemd_timer.rb +5 -0
- data/lib/chef/resource/chef_gem.rb +1 -1
- data/lib/chef/resource/execute.rb +8 -6
- data/lib/chef/resource/habitat_install.rb +2 -1
- data/lib/chef/resource/homebrew_cask.rb +19 -30
- data/lib/chef/resource/homebrew_tap.rb +32 -17
- data/lib/chef/resource/homebrew_update.rb +4 -4
- data/lib/chef/resource/powershell_package.rb +4 -0
- data/lib/chef/resource/snap_package.rb +23 -0
- data/lib/chef/resource/support/client.erb +4 -3
- data/lib/chef/resource/sysctl.rb +1 -0
- data/lib/chef/resource_inspector.rb +25 -7
- data/lib/chef/version.rb +1 -1
- data/lib/chef/win32/registry.rb +5 -0
- data/lib/chef/win32/security.rb +9 -0
- data/spec/functional/resource/cookbook_file_spec.rb +1 -1
- data/spec/functional/resource/remote_file_spec.rb +1 -1
- data/spec/integration/client/fips_spec.rb +11 -2
- data/spec/integration/client/open_ssl_spec.rb +20 -0
- data/spec/spec_helper.rb +4 -1
- data/spec/support/chef_helpers.rb +2 -2
- data/spec/support/platform_helpers.rb +28 -7
- data/spec/support/shared/functional/file_resource.rb +3 -3
- data/spec/unit/client_spec.rb +0 -16
- data/spec/unit/file_cache_spec.rb +64 -0
- data/spec/unit/mixin/homebrew_spec.rb +118 -0
- data/spec/unit/mixin/openssl_helper_spec.rb +6 -1
- data/spec/unit/provider/package/chocolatey_spec.rb +17 -12
- data/spec/unit/provider/package/homebrew_spec.rb +4 -1
- data/spec/unit/provider/package/windows_spec.rb +5 -5
- data/spec/unit/provider/package/zypper_spec.rb +0 -10
- data/spec/unit/provider/user/windows_spec.rb +1 -0
- data/spec/unit/resource_inspector_spec.rb +36 -0
- metadata +23 -10
- data/spec/unit/mixin/homebrew_user_spec.rb +0 -119
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9758afdcd61880d10d2e6fcbd0097a3dc94ead3ce67004ba317ed1754cf529d2
|
4
|
+
data.tar.gz: 2ea4ff22776735a4ec71531e3c188769328e3dab07f1930ab4f59c6c2032a9b4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6f54220fa4591d43a562055250981453252a30db5bed94473ba0350b4d147ae0eb517da7ab371ef5963b8c7675b06206a5366585a86234ef0ede60a2d92ebf28
|
7
|
+
data.tar.gz: d096c1a73764313a572382cb45963efac685f4a33655225b447b8f58f9dbcfb4abf732da9c7bd2c855bf526a28d195a2a3af49e36029b9f7941bbe4b2ad6682b
|
data/Gemfile
CHANGED
@@ -2,7 +2,7 @@ source "https://rubygems.org"
|
|
2
2
|
|
3
3
|
gem "chef", path: "."
|
4
4
|
|
5
|
-
gem "ohai", git: "https://github.com/chef/ohai.git", branch: "
|
5
|
+
gem "ohai", git: "https://github.com/chef/ohai.git", branch: "18-stable"
|
6
6
|
|
7
7
|
# Nwed to file a bug with rest-client. In the meantime, we can use this until they accept the update.
|
8
8
|
gem "rest-client", git: "https://github.com/chef/rest-client", branch: "jfm/ucrt_update1"
|
@@ -11,6 +11,13 @@ gem "ffi", ">= 1.15.5"
|
|
11
11
|
gem "chef-utils", path: File.expand_path("chef-utils", __dir__) if File.exist?(File.expand_path("chef-utils", __dir__))
|
12
12
|
gem "chef-config", path: File.expand_path("chef-config", __dir__) if File.exist?(File.expand_path("chef-config", __dir__))
|
13
13
|
|
14
|
+
# required for FIPS or bundler will pick up default openssl
|
15
|
+
install_if -> { RUBY_PLATFORM !~ /darwin/ } do
|
16
|
+
gem "openssl", "= 3.2.0"
|
17
|
+
end
|
18
|
+
|
19
|
+
gem "rdoc", "~> 6.4.1" # 6.4.1.1 required for CVE-2024-27281, allow patch upgrades
|
20
|
+
|
14
21
|
if File.exist?(File.expand_path("chef-bin", __dir__))
|
15
22
|
# bundling in a git checkout
|
16
23
|
gem "chef-bin", path: File.expand_path("chef-bin", __dir__)
|
@@ -49,7 +56,7 @@ group(:knife_windows_deps) do
|
|
49
56
|
end
|
50
57
|
|
51
58
|
group(:development, :test) do
|
52
|
-
gem "rake"
|
59
|
+
gem "rake", ">= 12.3.3"
|
53
60
|
gem "rspec"
|
54
61
|
gem "webmock"
|
55
62
|
gem "crack", "< 0.4.6" # due to https://github.com/jnunemaker/crack/pull/75
|
@@ -1,6 +1,6 @@
|
|
1
1
|
gemspec = instance_eval(File.read(File.expand_path("chef.gemspec", __dir__)))
|
2
2
|
|
3
|
-
gemspec.platform = Gem::Platform.new(%w{
|
3
|
+
gemspec.platform = Gem::Platform.new(%w{universal mingw-ucrt})
|
4
4
|
|
5
5
|
gemspec.add_dependency "win32-api", "~> 1.10.0"
|
6
6
|
gemspec.add_dependency "win32-event", "~> 0.6.1"
|
data/chef.gemspec
CHANGED
@@ -2,12 +2,12 @@ $:.unshift(File.dirname(__FILE__) + "/lib")
|
|
2
2
|
vs_path = File.expand_path("chef-utils/lib/chef-utils/version_string.rb", __dir__)
|
3
3
|
|
4
4
|
if File.exist?(vs_path)
|
5
|
-
#
|
6
|
-
|
7
|
-
|
8
|
-
# if the path doesn't exist then we're just in the wild gem and not in the git repo
|
9
|
-
require "chef-utils/version_string"
|
5
|
+
# include chef-utils/lib in the path if we're inside of chef vs. chef-utils gem
|
6
|
+
# but add it to the end of the search path
|
7
|
+
$: << (File.dirname(__FILE__) + "/chef-utils/lib")
|
10
8
|
end
|
9
|
+
# if the path doesn't exist then we're just in the wild gem and not in the git repo
|
10
|
+
require "chef-utils/version_string"
|
11
11
|
require "chef/version"
|
12
12
|
|
13
13
|
Gem::Specification.new do |s|
|
@@ -30,7 +30,7 @@ Gem::Specification.new do |s|
|
|
30
30
|
|
31
31
|
s.add_dependency "chef-config", "= #{Chef::VERSION}"
|
32
32
|
s.add_dependency "chef-utils", "= #{Chef::VERSION}"
|
33
|
-
s.add_dependency "train-core", "~> 3.10"
|
33
|
+
s.add_dependency "train-core", "~> 3.10", "<= 3.12.7"
|
34
34
|
s.add_dependency "train-winrm", ">= 0.2.5"
|
35
35
|
s.add_dependency "train-rest", ">= 0.4.1" # target mode with rest APIs
|
36
36
|
|
@@ -43,7 +43,7 @@ Gem::Specification.new do |s|
|
|
43
43
|
s.add_dependency "ohai", "~> 18.0"
|
44
44
|
s.add_dependency "inspec-core", ">= 5", "< 6"
|
45
45
|
|
46
|
-
s.add_dependency "ffi", ">= 1.15.5"
|
46
|
+
s.add_dependency "ffi", ">= 1.15.5", "<= 1.16.3"
|
47
47
|
s.add_dependency "ffi-yajl", "~> 2.2"
|
48
48
|
s.add_dependency "net-sftp", ">= 2.1.2", "< 5.0" # remote_file resource
|
49
49
|
s.add_dependency "net-ftp" # remote_file resource
|
@@ -65,7 +65,7 @@ Gem::Specification.new do |s|
|
|
65
65
|
|
66
66
|
s.add_dependency "aws-sdk-s3", "~> 1.91" # s3 recipe-url support
|
67
67
|
s.add_dependency "aws-sdk-secretsmanager", "~> 1.46"
|
68
|
-
s.add_dependency "vault", "~> 0.
|
68
|
+
s.add_dependency "vault", "~> 0.18.2" # hashi vault official client gem
|
69
69
|
s.bindir = "bin"
|
70
70
|
s.executables = %w{ }
|
71
71
|
|
data/lib/chef/client.rb
CHANGED
@@ -305,8 +305,6 @@ class Chef
|
|
305
305
|
# keep this inside the main loop to get exception backtraces
|
306
306
|
end_profiling
|
307
307
|
|
308
|
-
warn_if_eol
|
309
|
-
|
310
308
|
# rebooting has to be the last thing we do, no exceptions.
|
311
309
|
Chef::Platform::Rebooter.reboot_if_needed!(node)
|
312
310
|
rescue Exception => run_error
|
@@ -335,19 +333,6 @@ class Chef
|
|
335
333
|
# @todo make this stuff protected or private
|
336
334
|
#
|
337
335
|
|
338
|
-
# @api private
|
339
|
-
def warn_if_eol
|
340
|
-
require_relative "version"
|
341
|
-
|
342
|
-
# We make a release every year so take the version you're on + 2006 and you get
|
343
|
-
# the year it goes EOL
|
344
|
-
eol_year = 2006 + Gem::Version.new(Chef::VERSION).segments.first
|
345
|
-
|
346
|
-
if Time.now > Time.new(eol_year, 5, 01)
|
347
|
-
logger.warn("This release of #{ChefUtils::Dist::Infra::PRODUCT} became end of life (EOL) on May 1st #{eol_year}. Please update to a supported release to receive new features, bug fixes, and security updates.")
|
348
|
-
end
|
349
|
-
end
|
350
|
-
|
351
336
|
# @api private
|
352
337
|
def configure_formatters
|
353
338
|
formatters_for_run.map do |formatter_name, output_path|
|
@@ -50,7 +50,10 @@ class Chef
|
|
50
50
|
ignore_globs = []
|
51
51
|
if @ignore_file && readable_file_or_symlink?(@ignore_file)
|
52
52
|
File.foreach(@ignore_file) do |line|
|
53
|
-
|
53
|
+
unless COMMENTS_AND_WHITESPACE.match?(line)
|
54
|
+
line.strip!
|
55
|
+
ignore_globs << line
|
56
|
+
end
|
54
57
|
end
|
55
58
|
else
|
56
59
|
Chef::Log.debug("No chefignore file found. No files will be ignored!")
|
@@ -215,7 +215,7 @@ class Chef
|
|
215
215
|
Dir.entries(cookbook_path).each do |top_filename|
|
216
216
|
# Skip top-level directories starting with "."
|
217
217
|
top_path = File.join(cookbook_path, top_filename)
|
218
|
-
next if
|
218
|
+
next if top_filename.start_with?(".") && File.directory?(top_path)
|
219
219
|
|
220
220
|
# Use Find.find because it:
|
221
221
|
# (a) returns any children, recursively
|
@@ -43,9 +43,10 @@ class Chef
|
|
43
43
|
raise "get_filename: Cannot determine segment/filename for incoming filename #{filename}"
|
44
44
|
end
|
45
45
|
|
46
|
-
|
46
|
+
files_for_segment = @manifest.files_for(segment)
|
47
|
+
raise "No such segment #{segment} in cookbook #{@cookbook_name}" unless files_for_segment
|
47
48
|
|
48
|
-
found_manifest_record =
|
49
|
+
found_manifest_record = files_for_segment.find { |manifest_record| manifest_record[:path] == filename }
|
49
50
|
raise "No such file #{filename} in #{@cookbook_name}" unless found_manifest_record
|
50
51
|
|
51
52
|
cache_filename = File.join("cookbooks", @cookbook_name, found_manifest_record["path"])
|
@@ -280,8 +280,9 @@ class Chef
|
|
280
280
|
end
|
281
281
|
|
282
282
|
def ensure_cookbook_paths
|
283
|
+
cookbook_path = File.join(Chef::Config[:file_cache_path], "cookbooks")
|
283
284
|
cookbooks.each do |cookbook|
|
284
|
-
cb_dir = File.join(
|
285
|
+
cb_dir = File.join(cookbook_path, cookbook.name)
|
285
286
|
cookbook.root_paths = Array(cb_dir)
|
286
287
|
end
|
287
288
|
end
|
@@ -173,9 +173,9 @@ class Chef
|
|
173
173
|
def files_for(part)
|
174
174
|
return root_files if part.to_s == "root_files"
|
175
175
|
|
176
|
+
part_match = "#{part}/"
|
176
177
|
manifest[:all_files].select do |file|
|
177
|
-
|
178
|
-
part.to_s == seg
|
178
|
+
file[:name].start_with?(part_match)
|
179
179
|
end
|
180
180
|
end
|
181
181
|
|
data/lib/chef/exceptions.rb
CHANGED
@@ -170,7 +170,7 @@ class Chef
|
|
170
170
|
class PowershellCmdletException < RuntimeError; end
|
171
171
|
class LCMParser < RuntimeError; end
|
172
172
|
|
173
|
-
class
|
173
|
+
class CannotDetermineHomebrewPath < Package; end
|
174
174
|
class CannotDetermineWindowsInstallerType < Package; end
|
175
175
|
class NoWindowsPackageSource < Package; end
|
176
176
|
|
data/lib/chef/file_cache.rb
CHANGED
@@ -159,9 +159,24 @@ class Chef
|
|
159
159
|
# [String] - An array of file cache keys matching the glob
|
160
160
|
def find(glob_pattern)
|
161
161
|
keys = []
|
162
|
-
|
162
|
+
file_cache_dir = Chef::Util::PathHelper.escape_glob_dir(file_cache_path)
|
163
|
+
first_filename = Dir[file_cache_dir].first # directory of the cache
|
164
|
+
return keys unless first_filename
|
165
|
+
|
166
|
+
# TODO: The usage of Regexp.escape and the match here is likely
|
167
|
+
# vestigial, but since it's only getting called once per method, the
|
168
|
+
# effort needed to confirm that its removal won't break something else
|
169
|
+
# isn't worth it. A task for a brave soul ;-)
|
170
|
+
regexp_pattern = /^(#{Regexp.escape(first_filename) + File::Separator}).+/
|
171
|
+
|
172
|
+
files = Dir[File.join(file_cache_dir, glob_pattern)]
|
173
|
+
until files.empty?
|
174
|
+
f = files.shift
|
163
175
|
if File.file?(f)
|
164
|
-
|
176
|
+
# We remove the cache directory from the string of each entry
|
177
|
+
path_to_remove ||= f[regexp_pattern, 1]
|
178
|
+
f.delete_prefix!(path_to_remove)
|
179
|
+
keys << f
|
165
180
|
end
|
166
181
|
end
|
167
182
|
keys
|
data/lib/chef/formatters/doc.rb
CHANGED
@@ -57,7 +57,7 @@ class Chef
|
|
57
57
|
# Print out deprecations.
|
58
58
|
unless deprecations.empty?
|
59
59
|
puts_line ""
|
60
|
-
puts_line "Deprecation warnings that must be addressed before upgrading to
|
60
|
+
puts_line "Deprecation warnings that must be addressed before upgrading to #{ChefUtils::Dist::Infra::PRODUCT} #{Chef::VERSION.to_i + 1}:"
|
61
61
|
puts_line ""
|
62
62
|
deprecations.each do |message, details|
|
63
63
|
locations = details[:locations]
|
@@ -27,7 +27,7 @@ require "etc" unless defined?(Etc)
|
|
27
27
|
|
28
28
|
class Chef
|
29
29
|
module Mixin
|
30
|
-
module
|
30
|
+
module Homebrew
|
31
31
|
include Chef::Mixin::ShellOut
|
32
32
|
|
33
33
|
##
|
@@ -57,15 +57,19 @@ class Chef
|
|
57
57
|
@homebrew_owner_username
|
58
58
|
end
|
59
59
|
|
60
|
+
# Use homebrew_bin_path to return the path to the brew binary
|
61
|
+
# @param [String, Array(String)] brew_bin_path
|
62
|
+
# @return [String] path to the brew binary
|
60
63
|
def homebrew_bin_path(brew_bin_path = nil)
|
61
64
|
if brew_bin_path && ::File.exist?(brew_bin_path)
|
62
65
|
brew_bin_path
|
63
66
|
else
|
64
|
-
|
65
|
-
|
67
|
+
brew_path = which("brew", prepend_path: %w{/opt/homebrew/bin /usr/local/bin /home/linuxbrew/.linuxbrew/bin})
|
68
|
+
unless brew_path
|
69
|
+
raise Chef::Exceptions::CannotDetermineHomebrewPath, 'Couldn\'t find the "brew" executable anywhere on the path.'
|
70
|
+
end
|
66
71
|
|
67
|
-
|
68
|
-
end.first || nil
|
72
|
+
brew_path
|
69
73
|
end
|
70
74
|
end
|
71
75
|
|
@@ -73,18 +77,11 @@ class Chef
|
|
73
77
|
|
74
78
|
def calculate_owner
|
75
79
|
brew_path = homebrew_bin_path
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
raise Chef::Exceptions::CannotDetermineHomebrewOwner,
|
81
|
-
'Couldn\'t find the "brew" executable anywhere on the path.'
|
82
|
-
end
|
83
|
-
|
84
|
-
Chef::Log.debug "Found Homebrew owner #{Etc.getpwuid(owner).name}; executing `brew` commands as them"
|
85
|
-
owner
|
80
|
+
# By default, this follows symlinks which is what we want
|
81
|
+
owner_uid = ::File.stat(brew_path).uid
|
82
|
+
Chef::Log.debug "Found Homebrew owner #{Etc.getpwuid(owner_uid).name}; executing `brew` commands as them"
|
83
|
+
owner_uid
|
86
84
|
end
|
87
|
-
|
88
85
|
end
|
89
86
|
end
|
90
87
|
end
|
@@ -157,7 +157,7 @@ class Chef
|
|
157
157
|
raise TypeError, "curve must be a string" unless curve.is_a?(String)
|
158
158
|
raise ArgumentError, "Specified curve is not available on this system" unless %w{prime256v1 secp384r1 secp521r1}.include?(curve)
|
159
159
|
|
160
|
-
::OpenSSL::PKey::EC.
|
160
|
+
::OpenSSL::PKey::EC.generate(curve)
|
161
161
|
end
|
162
162
|
|
163
163
|
# generate pem format of the public key given a private key
|
@@ -170,18 +170,7 @@ class Chef
|
|
170
170
|
key_content = ::File.exist?(priv_key) ? File.read(priv_key) : priv_key
|
171
171
|
key = ::OpenSSL::PKey::EC.new key_content, priv_key_password
|
172
172
|
|
173
|
-
|
174
|
-
group = ::OpenSSL::PKey::EC::Group.new(key.group.curve_name)
|
175
|
-
# Get Generator point & public point (priv * generator)
|
176
|
-
generator = group.generator
|
177
|
-
pub_point = generator.mul(key.private_key)
|
178
|
-
key.public_key = pub_point
|
179
|
-
|
180
|
-
# Public Key in pem
|
181
|
-
public_key = ::OpenSSL::PKey::EC.new
|
182
|
-
public_key.group = group
|
183
|
-
public_key.public_key = pub_point
|
184
|
-
public_key.to_pem
|
173
|
+
key.public_to_pem
|
185
174
|
end
|
186
175
|
|
187
176
|
# generate a pem file given a cipher, key, an optional key_password
|
data/lib/chef/node/attribute.rb
CHANGED
@@ -570,7 +570,7 @@ class Chef
|
|
570
570
|
]
|
571
571
|
|
572
572
|
ret = components.inject(NIL) do |merged, component|
|
573
|
-
hash_only_merge!(merged, component)
|
573
|
+
component == NIL ? merged : hash_only_merge!(merged, component)
|
574
574
|
end
|
575
575
|
ret == NIL ? nil : ret
|
576
576
|
end
|
@@ -584,7 +584,7 @@ class Chef
|
|
584
584
|
def merge_defaults(path)
|
585
585
|
DEFAULT_COMPONENTS.inject(NIL) do |merged, component_ivar|
|
586
586
|
component_value = apply_path(instance_variable_get(component_ivar), path)
|
587
|
-
deep_merge!(merged, component_value)
|
587
|
+
component_value == NIL ? merged : deep_merge!(merged, component_value)
|
588
588
|
end
|
589
589
|
end
|
590
590
|
|
@@ -597,7 +597,7 @@ class Chef
|
|
597
597
|
def merge_overrides(path)
|
598
598
|
OVERRIDE_COMPONENTS.inject(NIL) do |merged, component_ivar|
|
599
599
|
component_value = apply_path(instance_variable_get(component_ivar), path)
|
600
|
-
deep_merge!(merged, component_value)
|
600
|
+
component_value == NIL ? merged : deep_merge!(merged, component_value)
|
601
601
|
end
|
602
602
|
end
|
603
603
|
|
@@ -628,10 +628,6 @@ class Chef
|
|
628
628
|
elsif merge_onto.is_a?(Array) && merge_with.is_a?(Array)
|
629
629
|
merge_onto |= merge_with
|
630
630
|
|
631
|
-
# If merge_with is NIL, don't replace merge_onto
|
632
|
-
elsif merge_with == NIL
|
633
|
-
merge_onto
|
634
|
-
|
635
631
|
# In all other cases, replace merge_onto with merge_with
|
636
632
|
else
|
637
633
|
if merge_with.is_a?(Hash)
|
@@ -661,10 +657,6 @@ class Chef
|
|
661
657
|
end
|
662
658
|
merge_onto
|
663
659
|
|
664
|
-
# If merge_with is NIL, don't replace merge_onto
|
665
|
-
elsif merge_with == NIL
|
666
|
-
merge_onto
|
667
|
-
|
668
660
|
# In all other cases, replace merge_onto with merge_with
|
669
661
|
else
|
670
662
|
if merge_with.is_a?(Hash)
|
@@ -33,18 +33,25 @@ class Chef
|
|
33
33
|
end
|
34
34
|
|
35
35
|
def convert_value(value)
|
36
|
-
# The order in this case statement is *important*.
|
37
|
-
# ImmutableMash and ImmutableArray should be tested first,
|
38
|
-
# as this saves unnecessary creation of intermediate objects
|
39
36
|
case value
|
40
|
-
when ImmutableMash, ImmutableArray
|
41
|
-
value
|
42
37
|
when Hash
|
43
|
-
ImmutableMash
|
38
|
+
if ImmutableMash === value
|
39
|
+
# Save an object creation
|
40
|
+
value
|
41
|
+
else
|
42
|
+
ImmutableMash.new(value, __root__, __node__, __precedence__)
|
43
|
+
end
|
44
44
|
when Array
|
45
|
-
ImmutableArray
|
45
|
+
if ImmutableArray === value
|
46
|
+
# Save an object creation
|
47
|
+
value
|
48
|
+
else
|
49
|
+
ImmutableArray.new(value, __root__, __node__, __precedence__)
|
50
|
+
end
|
46
51
|
else
|
47
|
-
|
52
|
+
# We return any already frozen strings, since that's common over the course of a run.
|
53
|
+
# Check `frozen?` first since that's faster than a Class comparison
|
54
|
+
value.frozen? && String === value ? value : safe_dup(value).freeze
|
48
55
|
end
|
49
56
|
end
|
50
57
|
|
@@ -37,7 +37,8 @@ class Chef
|
|
37
37
|
def [](*args)
|
38
38
|
ret = super
|
39
39
|
key = args.first
|
40
|
-
next_path = [ __path__, convert_key(key) ].flatten
|
40
|
+
next_path = [ __path__, convert_key(key) ].flatten
|
41
|
+
next_path.compact!
|
41
42
|
copy_state_to(ret, next_path)
|
42
43
|
end
|
43
44
|
|
@@ -45,7 +46,8 @@ class Chef
|
|
45
46
|
ret = super
|
46
47
|
key = args.first
|
47
48
|
value = args.last
|
48
|
-
next_path = [ __path__, convert_key(key) ].flatten
|
49
|
+
next_path = [ __path__, convert_key(key) ].flatten
|
50
|
+
next_path.compact!
|
49
51
|
send_attribute_changed_event(next_path, value)
|
50
52
|
copy_state_to(ret, next_path)
|
51
53
|
end
|
@@ -77,7 +79,8 @@ class Chef
|
|
77
79
|
end
|
78
80
|
|
79
81
|
def send_reset_cache(path = nil, key = nil)
|
80
|
-
next_path = [ path, key ].flatten
|
82
|
+
next_path = [ path, key ].flatten
|
83
|
+
next_path.compact!
|
81
84
|
__root__.reset_cache(next_path.first) if !__root__.nil? && __root__.respond_to?(:reset_cache)
|
82
85
|
end
|
83
86
|
|
@@ -132,6 +132,9 @@ class Chef
|
|
132
132
|
|
133
133
|
node.consume_external_attrs(ohai_data, json_attribs)
|
134
134
|
|
135
|
+
# Preserve the fall back to loading an unencrypted data bag item if the item we're trying to load isn't actually a vault item.
|
136
|
+
set_databag_fallback
|
137
|
+
|
135
138
|
setup_run_list_override
|
136
139
|
|
137
140
|
expand_run_list
|
@@ -191,6 +194,11 @@ class Chef
|
|
191
194
|
run_context
|
192
195
|
end
|
193
196
|
|
197
|
+
# Preserve the fall back to loading an unencrypted data bag item if the item we're trying to load isn't actually a vault item.
|
198
|
+
def set_databag_fallback
|
199
|
+
node.default["chef-vault"]["databag_fallback"] = ChefUtils.kitchen?(node)
|
200
|
+
end
|
201
|
+
|
194
202
|
# Sets `run_list` on the node from the policy, sets `roles` and `recipes`
|
195
203
|
# attributes on the node accordingly.
|
196
204
|
#
|
@@ -144,12 +144,16 @@ class Chef
|
|
144
144
|
def check_resource_semantics!; end
|
145
145
|
|
146
146
|
def get_choco_version
|
147
|
-
|
147
|
+
# We need a different way to get the version than by simply calling "choco --version".
|
148
|
+
# If the license file is installed (for business customers) but not the Chocolatey.Extension (because you're using the choco resource to install it)
|
149
|
+
# then you get a license error. This method bypasses that by getting the version from the exe directly instead of invoking it.
|
150
|
+
# deprecated: @get_choco_version ||= powershell_exec!("#{choco_exe} --version").result
|
151
|
+
@get_choco_version ||= powershell_exec!("Get-ItemProperty #{choco_exe} | select-object -expandproperty versioninfo | select-object -expandproperty productversion").result
|
148
152
|
end
|
149
153
|
|
150
154
|
# Choco V2 uses 'Search' for remote repositories and 'List' for local packages
|
151
155
|
def query_command
|
152
|
-
return "list" if
|
156
|
+
return "list" if Gem::Dependency.new("", "< 1.4.0").match?("", get_choco_version)
|
153
157
|
|
154
158
|
"search"
|
155
159
|
end
|
@@ -167,22 +171,34 @@ class Chef
|
|
167
171
|
true
|
168
172
|
end
|
169
173
|
|
170
|
-
#
|
171
|
-
#
|
172
|
-
#
|
173
|
-
#
|
174
|
-
#
|
174
|
+
# Find the set of packages to ask the chocolatey server about
|
175
|
+
#
|
176
|
+
# if walk_resource_tree is true, this finds _all_ of the packages that
|
177
|
+
# we have referenced anywhere in our recipes - this is so we can
|
178
|
+
# attempt to query them all in a single transaction. However,
|
179
|
+
# currently we don't do that - see the comment on available_packages
|
180
|
+
# for details of the why, but the TL;DR is that the public chocolatey
|
181
|
+
# servers do not support `or` type queries properly.
|
182
|
+
#
|
183
|
+
# If walk_resource_tree is false, we don't do any of that - we just filter
|
184
|
+
# the package list based on cache data. This is the default due to reasons
|
185
|
+
# explained in the comment on available_packages - the goal is to eventually
|
186
|
+
# turn this back on, hence the default false parameter here.
|
175
187
|
#
|
176
188
|
# @return [Array] List of chocolatey packages referenced in the run list
|
177
|
-
def collect_package_requests(ignore_list: [])
|
189
|
+
def collect_package_requests(ignore_list: [], walk_resource_tree: false)
|
178
190
|
return ["*"] if new_resource.bulk_query || Chef::Config[:always_use_bulk_chocolatey_package_list]
|
179
191
|
|
180
|
-
|
181
|
-
|
182
|
-
|
192
|
+
if walk_resource_tree
|
193
|
+
# Get to the root of the resource collection
|
194
|
+
rc = run_context.parent_run_context || run_context
|
195
|
+
rc = rc.parent_run_context while rc.parent_run_context
|
183
196
|
|
184
|
-
|
185
|
-
|
197
|
+
package_collection = package_name_array
|
198
|
+
package_collection += nested_package_resources(rc.resource_collection)
|
199
|
+
else
|
200
|
+
package_collection = package_name_array
|
201
|
+
end
|
186
202
|
# downcase the array and uniq. sorted for easier testing...
|
187
203
|
package_collection.uniq.sort.filter { |pkg| !ignore_list.include?(pkg) }
|
188
204
|
end
|
@@ -224,7 +240,7 @@ class Chef
|
|
224
240
|
@choco_exe ||= begin
|
225
241
|
# if this check is in #define_resource_requirements, it won't get
|
226
242
|
# run before choco.exe gets called from #load_current_resource.
|
227
|
-
exe_path = ::File.join(choco_install_path, "
|
243
|
+
exe_path = ::File.join(choco_install_path, "choco.exe")
|
228
244
|
raise Chef::Exceptions::MissingLibrary, CHOCO_MISSING_MSG unless ::File.exist?(exe_path)
|
229
245
|
|
230
246
|
exe_path
|
@@ -339,22 +355,33 @@ class Chef
|
|
339
355
|
@@choco_available_packages[new_resource.list_options] = {}
|
340
356
|
end
|
341
357
|
|
342
|
-
#
|
343
|
-
#
|
358
|
+
# This would previously grab 25 packages at a time, which previously worked - however,
|
359
|
+
# upstream changed and it turns out this was only working by accident - see
|
360
|
+
# https://github.com/chocolatey/choco/issues/2116 for this. So the TL;DR ends up
|
361
|
+
# being that this can be re-enabled when the chocolatey server actually supports an
|
362
|
+
# or operator. So it makes sense to leave the logic here for this split, while we
|
363
|
+
# work with upstream to get this to be a working feature there
|
364
|
+
#
|
365
|
+
# Foot guns: there is a --id-starts-with for chocolatey, which you'd think would work,
|
366
|
+
# but that actually fails on public chocolatey as well, because it seems to do the filtering
|
367
|
+
# locally. Which means it too will omit a lot of results (this is also corroborated by
|
368
|
+
# the 2116 issue above).
|
344
369
|
#
|
345
|
-
#
|
346
|
-
#
|
370
|
+
# collect_package_requests, however, continues to be useful here because it filters
|
371
|
+
# the already cached things from the list. However, for now it will no longer walk the
|
372
|
+
# resource tree until 2116 can be sorted out. When we regain that ability, we should
|
373
|
+
# re-evaluate this, since it does save a LOT of API requests!
|
347
374
|
collect_package_requests(
|
348
375
|
ignore_list: @@choco_available_packages[new_resource.list_options].keys
|
349
|
-
).
|
376
|
+
).each do |pkg_set|
|
350
377
|
available_versions =
|
351
378
|
begin
|
352
379
|
cmd = [ query_command, "-r" ]
|
353
380
|
|
354
381
|
# Chocolatey doesn't actually take a wildcard for this query, however
|
355
382
|
# it will return all packages when using '*' as a query
|
356
|
-
unless pkg_set ==
|
357
|
-
cmd
|
383
|
+
unless pkg_set == "*"
|
384
|
+
cmd << pkg_set
|
358
385
|
end
|
359
386
|
cmd += common_options
|
360
387
|
cmd.push( new_resource.list_options ) if new_resource.list_options
|
@@ -383,10 +410,12 @@ class Chef
|
|
383
410
|
#
|
384
411
|
# @return [Hash] name-to-version mapping of installed packages
|
385
412
|
def installed_packages
|
386
|
-
|
387
|
-
|
388
|
-
|
413
|
+
# Logic here must be either use_choco_list is false _and_ always_use_choco_list is
|
414
|
+
# falsy, since the global overrides the local
|
415
|
+
if new_resource.use_choco_list == false && !Chef::Config[:always_use_choco_list]
|
389
416
|
installed_packages_via_disk
|
417
|
+
else
|
418
|
+
installed_packages_via_choco
|
390
419
|
end
|
391
420
|
end
|
392
421
|
|
@@ -413,8 +442,8 @@ class Chef
|
|
413
442
|
# that contains all possible package folders, and so we push our
|
414
443
|
# guess to the front as an optimization.
|
415
444
|
target_dirs << targets.first.downcase if targets.length == 1
|
416
|
-
if targets.
|
417
|
-
target_dirs << targets
|
445
|
+
if targets.is_a?(String)
|
446
|
+
target_dirs << targets.downcase
|
418
447
|
end
|
419
448
|
target_dirs += get_local_pkg_dirs(choco_lib_path)
|
420
449
|
fetch_package_versions(choco_lib_path, target_dirs, targets)
|
@@ -465,6 +494,7 @@ class Chef
|
|
465
494
|
# Fetch the local package versions from chocolatey
|
466
495
|
def fetch_package_versions(base_dir, target_dirs, targets)
|
467
496
|
pkg_versions = {}
|
497
|
+
targets = [targets] if targets.is_a?(String)
|
468
498
|
target_dirs.each do |dir|
|
469
499
|
pkg_versions.merge!(get_pkg_data(::File.join(base_dir, dir)))
|
470
500
|
# return early if we found the single package version we were looking for
|