chef 19.2.12 → 19.3.14
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 +11 -16
- data/README.md +6 -1
- data/Rakefile +1 -0
- data/chef-universal-mingw-ucrt.gemspec +9 -2
- data/chef.gemspec +18 -8
- data/lib/chef/application/client.rb +7 -1
- data/lib/chef/chef_fs/file_system/chef_server/cookbook_dir.rb +1 -1
- data/lib/chef/client.rb +22 -4
- data/lib/chef/compliance/runner.rb +19 -1
- data/lib/chef/cookbook/gem_installer.rb +1 -1
- data/lib/chef/cookbook_uploader.rb +1 -1
- data/lib/chef/dsl/rest_resource.rb +63 -12
- data/lib/chef/file_access_control/windows.rb +6 -0
- data/lib/chef/file_access_control.rb +12 -1
- data/lib/chef/handler/slow_report.rb +3 -4
- data/lib/chef/licensing.rb +26 -6
- data/lib/chef/node.rb +13 -1
- data/lib/chef/policy_builder/expand_node_object.rb +12 -1
- data/lib/chef/policy_builder/policyfile.rb +12 -0
- data/lib/chef/property.rb +1 -1
- data/lib/chef/provider/file/content.rb +3 -2
- data/lib/chef/provider/file.rb +5 -2
- data/lib/chef/provider/ifconfig/redhat.rb +1 -1
- data/lib/chef/provider/package/dnf/dnf_helper.py +355 -65
- data/lib/chef/provider/package/dnf/python_helper.rb +6 -3
- data/lib/chef/provider/package/dnf.rb +24 -5
- data/lib/chef/provider/package/yum.rb +1 -1
- data/lib/chef/provider/package/yum_tm.rb +1 -1
- data/lib/chef/resource/_rest_resource.rb +4 -2
- data/lib/chef/resource/build_essential.rb +10 -1
- data/lib/chef/resource/execute.rb +0 -15
- data/lib/chef/resource/yum_package.rb +1 -1
- data/lib/chef/target_io/support.rb +1 -1
- data/lib/chef/target_io/train/dir.rb +1 -1
- data/lib/chef/target_io/train/file.rb +5 -5
- data/lib/chef/target_io/train/fileutils.rb +1 -1
- data/lib/chef/version.rb +1 -1
- data/lib/chef/win32/version.rb +17 -16
- metadata +37 -13
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ed0f7eae7503218a435d2f704ded8090f173948c680b567931912640b7eee49d
|
|
4
|
+
data.tar.gz: 50246c34f0fd8e7a121a3e321133ddf837773f1a8709ef8d8bc0c2458f281d2d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f86eb78537de28cbe45c8a2b072486339c402d6e3a485faab22adf4324c5e3c55f8e353af7ef115f5975e04a2645db7911efa9746045c40cdffdcac5527c33b7
|
|
7
|
+
data.tar.gz: 63dfa9792e78efecefd529689becf43555d981a6e1ec2b961b7f12340ef92e2d0e30104c4dcb01fa6e967f79bd629f2c465e74b0a037aee95376226a5983d9eb
|
data/Gemfile
CHANGED
|
@@ -10,11 +10,7 @@ gem "cheffish", git: "https://github.com/chef/cheffish.git", branch: "main"
|
|
|
10
10
|
# Using our fork until they accept it.
|
|
11
11
|
gem "rest-client", git: "https://github.com/chef/rest-client", branch: "jfm/ucrt_update1"
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
gem "ffi", ">= 1.15.5", "< 1.18.0"
|
|
15
|
-
else
|
|
16
|
-
gem "ffi", ">= 1.15.5", force_ruby_platform: true
|
|
17
|
-
end
|
|
13
|
+
gem "ffi", ">= 1.15.5", force_ruby_platform: true
|
|
18
14
|
|
|
19
15
|
gem "chef-utils", path: File.expand_path("chef-utils", __dir__) if File.exist?(File.expand_path("chef-utils", __dir__))
|
|
20
16
|
gem "chef-config", path: File.expand_path("chef-config", __dir__) if File.exist?(File.expand_path("chef-config", __dir__))
|
|
@@ -28,23 +24,23 @@ if File.exist?(File.expand_path("chef-bin", __dir__))
|
|
|
28
24
|
# bundling in a git checkout
|
|
29
25
|
gem "chef-bin", path: File.expand_path("chef-bin", __dir__)
|
|
30
26
|
else
|
|
31
|
-
# bundling in
|
|
27
|
+
# bundling in packaging
|
|
32
28
|
gem "chef-bin" # rubocop:disable Bundler/DuplicatedGem
|
|
33
29
|
end
|
|
34
30
|
|
|
35
|
-
group(:
|
|
31
|
+
group(:packaging) do
|
|
36
32
|
gem "appbundler"
|
|
37
33
|
gem "rb-readline"
|
|
38
34
|
gem "inspec-core-bin", "= 7.0.107" # need to provide the binaries for inspec
|
|
39
35
|
gem "chef-vault"
|
|
40
36
|
end
|
|
41
37
|
|
|
42
|
-
gem "repl_type_completor", "~> 0.1.
|
|
38
|
+
gem "repl_type_completor", "~> 0.1.15" # deprecation warnings in chef-shell
|
|
43
39
|
|
|
44
|
-
group(:
|
|
40
|
+
group(:packaging, :pry) do
|
|
45
41
|
# Locked because pry-byebug is broken with 13+.
|
|
46
42
|
# some work is ongoing? https://github.com/deivid-rodriguez/pry-byebug/issues/343
|
|
47
|
-
gem "pry", "~> 0.
|
|
43
|
+
gem "pry", "~> 0.16.0"
|
|
48
44
|
# byebug does not install on freebsd on ruby 3.0
|
|
49
45
|
install_if -> { !RUBY_PLATFORM.match?(/freebsd/i) } do
|
|
50
46
|
gem "pry-byebug"
|
|
@@ -59,11 +55,6 @@ group(:ruby_shadow) do
|
|
|
59
55
|
end
|
|
60
56
|
end
|
|
61
57
|
|
|
62
|
-
# deps that cannot be put in the knife gem because they require a compiler and fail on windows nodes
|
|
63
|
-
group(:knife_windows_deps) do
|
|
64
|
-
gem "ed25519", "~> 1.2" # ed25519 ssh key support
|
|
65
|
-
end
|
|
66
|
-
|
|
67
58
|
group(:development, :test) do
|
|
68
59
|
gem "rake", ">= 12.3.3"
|
|
69
60
|
gem "rspec"
|
|
@@ -76,4 +67,8 @@ instance_eval(ENV["GEMFILE_MOD"]) if ENV["GEMFILE_MOD"]
|
|
|
76
67
|
|
|
77
68
|
# If you want to load debugging tools into the bundle exec sandbox,
|
|
78
69
|
# add these additional dependencies into Gemfile.local
|
|
79
|
-
|
|
70
|
+
#
|
|
71
|
+
# But doing eval_gemfile("./Gemfile.local") breaks dependabot, so a
|
|
72
|
+
# bit of indirection here
|
|
73
|
+
local_gemfile = File.join(__dir__, "Gemfile.local")
|
|
74
|
+
eval(File.read(local_gemfile)) if File.exist?(local_gemfile)
|
data/README.md
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
# Chef Infra
|
|
2
|
-
|
|
2
|
+
|
|
3
3
|
[](https://buildkite.com/chef-oss/chef-chef-main-verify)
|
|
4
|
+
[](https://github.com/chef/chef/actions/workflows/lint.yml)
|
|
5
|
+
[](https://github.com/chef/chef/actions/workflows/kitchen.yml)
|
|
6
|
+
[](https://github.com/chef/chef/actions/workflows/unit_specs.yml)
|
|
7
|
+
[](https://github.com/chef/chef/actions/workflows/func_spec.yml)
|
|
4
8
|
[](https://badge.fury.io/rb/chef)
|
|
5
9
|
[](https://github.com/chef/chef/blob/main/docs/dev/design_documents/client_release_cadence.md)
|
|
10
|
+
[](https://github.com/chef/chef/actions/workflows/dependabot/dependabot-updates)
|
|
6
11
|
|
|
7
12
|
**Umbrella Project**: [Chef Infra](https://github.com/chef/chef-oss-practices/blob/main/projects/chef-infra.md)
|
|
8
13
|
|
data/Rakefile
CHANGED
|
@@ -25,6 +25,7 @@ begin
|
|
|
25
25
|
require_relative "tasks/dependencies"
|
|
26
26
|
require_relative "tasks/docs"
|
|
27
27
|
require_relative "tasks/spellcheck"
|
|
28
|
+
require_relative "tasks/target_mode"
|
|
28
29
|
require_relative "chef-utils/lib/chef-utils/dist" unless defined?(ChefUtils::Dist)
|
|
29
30
|
rescue LoadError => e
|
|
30
31
|
puts "Skipping missing rake dep: #{e}"
|
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
|
|
1
|
+
# rubocop:disable Chef/Ruby/GemspecLicense
|
|
2
|
+
# License is in the included gemspec.
|
|
3
|
+
gemspec = Gem::Specification.load(File.expand_path("chef.gemspec", __dir__))
|
|
4
|
+
|
|
5
|
+
# In situations like Dependabot, the above returns nil, so create an empty
|
|
6
|
+
# gemspec so that the rest of this file doesn't error out trying to call
|
|
7
|
+
# methods on nil
|
|
8
|
+
gemspec = Gem::Specification.new unless gemspec
|
|
2
9
|
|
|
3
10
|
gemspec.platform = Gem::Platform.new(%w{universal mingw-ucrt})
|
|
4
11
|
|
|
@@ -6,7 +13,7 @@ gemspec.add_dependency "win32-api", "~> 1.10.0"
|
|
|
6
13
|
gemspec.add_dependency "win32-event", "~> 0.6.1"
|
|
7
14
|
# TODO: Relax this pin and make the necessary updaets. The issue originally
|
|
8
15
|
# leading to this pin has been fixed in 0.6.5.
|
|
9
|
-
gemspec.add_dependency "win32-eventlog", "0.6.
|
|
16
|
+
gemspec.add_dependency "win32-eventlog", "0.6.7"
|
|
10
17
|
gemspec.add_dependency "win32-mmap", "~> 0.4.1"
|
|
11
18
|
gemspec.add_dependency "win32-mutex", "~> 0.4.2"
|
|
12
19
|
gemspec.add_dependency "win32-process", "~> 0.9"
|
data/chef.gemspec
CHANGED
|
@@ -10,8 +10,17 @@ if File.exist?(vs_path)
|
|
|
10
10
|
$: << File.join(file_directory, "chef-utils", "lib")
|
|
11
11
|
end
|
|
12
12
|
# if the path doesn't exist then we're just in the wild gem and not in the git repo
|
|
13
|
-
|
|
14
|
-
require "chef/
|
|
13
|
+
begin
|
|
14
|
+
require "chef-utils/version_string"
|
|
15
|
+
require "chef/version"
|
|
16
|
+
rescue LoadError
|
|
17
|
+
# lib/ is not available in all contexts (e.g. Dependabot security scans
|
|
18
|
+
# fetch only gemspec files, not the full repo). Provide a stub so the
|
|
19
|
+
# gemspec can still be evaluated to inspect its dependencies.
|
|
20
|
+
module Chef
|
|
21
|
+
VERSION = "0.0.0".freeze
|
|
22
|
+
end
|
|
23
|
+
end
|
|
15
24
|
|
|
16
25
|
Gem::Specification.new do |s|
|
|
17
26
|
s.name = "chef"
|
|
@@ -25,10 +34,11 @@ Gem::Specification.new do |s|
|
|
|
25
34
|
s.email = "adam@chef.io"
|
|
26
35
|
s.homepage = "https://www.chef.io"
|
|
27
36
|
|
|
37
|
+
# help dependabot by specifying a default. If the default is in
|
|
38
|
+
# the 'else', dependabot misses it and falls back to a very old ruby
|
|
39
|
+
s.required_ruby_version = ">= 3.1.0"
|
|
28
40
|
if RUBY_PLATFORM =~ /aix/
|
|
29
41
|
s.required_ruby_version = ">= 3.0.3"
|
|
30
|
-
else
|
|
31
|
-
s.required_ruby_version = ">= 3.1.0"
|
|
32
42
|
end
|
|
33
43
|
|
|
34
44
|
s.add_dependency "chef-config", "= #{Chef::VERSION}"
|
|
@@ -41,13 +51,13 @@ Gem::Specification.new do |s|
|
|
|
41
51
|
s.add_dependency "mixlib-cli", ">= 2.1.1", "< 3.0"
|
|
42
52
|
s.add_dependency "mixlib-log", ">= 2.0.3", "< 4.0"
|
|
43
53
|
s.add_dependency "mixlib-authentication", ">= 2.1", "< 4"
|
|
44
|
-
s.add_dependency "mixlib-shellout", "
|
|
54
|
+
s.add_dependency "mixlib-shellout", ">= 3.3.8", "< 3.5.0"
|
|
45
55
|
s.add_dependency "mixlib-archive", ">= 0.4", "< 2.0"
|
|
46
56
|
s.add_dependency "ohai", "~> 19.0"
|
|
47
57
|
s.add_dependency "inspec-core", "~> 7.0.107"
|
|
48
58
|
|
|
49
59
|
s.add_dependency "ffi", ">= 1.15.5", "< 1.18.0"
|
|
50
|
-
s.add_dependency "ffi-yajl", "
|
|
60
|
+
s.add_dependency "ffi-yajl", ">= 2.2", "< 4.0"
|
|
51
61
|
s.add_dependency "net-sftp", ">= 2.1.2", "< 5.0" # remote_file resource
|
|
52
62
|
s.add_dependency "net-ftp" # remote_file resource
|
|
53
63
|
s.add_dependency "ed25519", "~> 1.2" # ssh-ed25519 support for target mode
|
|
@@ -65,14 +75,14 @@ Gem::Specification.new do |s|
|
|
|
65
75
|
s.add_dependency "csv", "~> 3.3.5" # really needs to come from inspec?
|
|
66
76
|
s.add_dependency "syslog-logger", "~> 1.6"
|
|
67
77
|
s.add_dependency "unf_ext", "~> 0.0.9.1" # older platforms
|
|
68
|
-
s.add_dependency "uri", "
|
|
78
|
+
s.add_dependency "uri", ">= 1.0.4", "< 1.2.0" # CVE-2025-61594 fixed in >= 1.0.4
|
|
69
79
|
s.add_dependency "corefoundation", "~> 0.3.4" # macos_userdefaults resource
|
|
70
80
|
|
|
71
81
|
s.add_dependency "proxifier2", "~> 1.1"
|
|
72
82
|
|
|
73
83
|
s.add_dependency "aws-sdk-s3", "~> 1.91" # s3 recipe-url support
|
|
74
84
|
s.add_dependency "aws-sdk-secretsmanager", "~> 1.46"
|
|
75
|
-
s.add_dependency "vault", "
|
|
85
|
+
s.add_dependency "vault", ">= 0.18.2", "< 0.21.0" # hashi vault official client gem
|
|
76
86
|
s.add_dependency "chef-licensing", "~> 1.3"
|
|
77
87
|
|
|
78
88
|
s.bindir = "bin"
|
|
@@ -127,8 +127,14 @@ class Chef::Application::Client < Chef::Application::Base
|
|
|
127
127
|
train_config = Train.unpack_target_from_uri(Chef::Config.target_mode.host)
|
|
128
128
|
Chef::Config.target_mode = train_config
|
|
129
129
|
end
|
|
130
|
+
# Save the operator's identity BEFORE enabling target mode.
|
|
131
|
+
# client_key must be captured here because its default path changes once
|
|
132
|
+
# target_mode.enabled = true (it would resolve to /etc/chef/<target>/client.pem
|
|
133
|
+
# instead of the workstation's /etc/chef/client.pem).
|
|
134
|
+
Chef::Config[:api_client_name] ||= Chef::Config[:node_name]
|
|
135
|
+
Chef::Config[:api_client_key] ||= Chef::Config[:client_key]
|
|
130
136
|
Chef::Config.target_mode.enabled = true
|
|
131
|
-
Chef::Config.node_name = Chef::Config.target_mode.host
|
|
137
|
+
Chef::Config.node_name = Chef::Config.target_mode.host
|
|
132
138
|
end
|
|
133
139
|
|
|
134
140
|
if config[:credentials]
|
data/lib/chef/client.rb
CHANGED
|
@@ -385,8 +385,8 @@ class Chef
|
|
|
385
385
|
#
|
|
386
386
|
# @api private
|
|
387
387
|
def rest
|
|
388
|
-
@rest ||= Chef::ServerAPI.new(Chef::Config[:chef_server_url], client_name:
|
|
389
|
-
signing_key_filename:
|
|
388
|
+
@rest ||= Chef::ServerAPI.new(Chef::Config[:chef_server_url], client_name: api_client_name,
|
|
389
|
+
signing_key_filename: api_client_key)
|
|
390
390
|
end
|
|
391
391
|
|
|
392
392
|
# A rest object with validate_utf8 set to false. This will not throw exceptions
|
|
@@ -397,8 +397,26 @@ class Chef
|
|
|
397
397
|
# @api private
|
|
398
398
|
def rest_clean
|
|
399
399
|
@rest_clean ||=
|
|
400
|
-
Chef::ServerAPI.new(Chef::Config[:chef_server_url], client_name:
|
|
401
|
-
signing_key_filename:
|
|
400
|
+
Chef::ServerAPI.new(Chef::Config[:chef_server_url], client_name: api_client_name,
|
|
401
|
+
signing_key_filename: api_client_key, validate_utf8: false)
|
|
402
|
+
end
|
|
403
|
+
|
|
404
|
+
# Returns the client name to use for Chef Server API auth. In target mode the
|
|
405
|
+
# operator's original identity is stored in api_client_name so that API calls
|
|
406
|
+
# authenticate as the workstation client rather than as the target node.
|
|
407
|
+
#
|
|
408
|
+
# @api private
|
|
409
|
+
def api_client_name
|
|
410
|
+
Chef::Config[:api_client_name] || node_name
|
|
411
|
+
end
|
|
412
|
+
|
|
413
|
+
# Returns the signing key path to use for Chef Server API auth. In target mode
|
|
414
|
+
# the operator's original key is stored in api_client_key so that API calls
|
|
415
|
+
# use the workstation key rather than the target node's key.
|
|
416
|
+
#
|
|
417
|
+
# @api private
|
|
418
|
+
def api_client_key
|
|
419
|
+
Chef::Config[:api_client_key] || Chef::Config[:client_key]
|
|
402
420
|
end
|
|
403
421
|
|
|
404
422
|
#
|
|
@@ -77,14 +77,32 @@ class Chef
|
|
|
77
77
|
logger.debug("#{self.class}##{__method__}: enabling Compliance Phase")
|
|
78
78
|
|
|
79
79
|
report_with_interval
|
|
80
|
+
@compliance_phase_completed = true
|
|
80
81
|
end
|
|
81
82
|
|
|
82
|
-
def run_failed(
|
|
83
|
+
def run_failed(exception, _run_status)
|
|
83
84
|
# If the run has failed because our own validation of compliance
|
|
84
85
|
# phase configuration has failed, we don't want to submit a report
|
|
85
86
|
# because we're still not configured correctly.
|
|
86
87
|
return unless enabled? && @validation_passed
|
|
87
88
|
|
|
89
|
+
# A reboot exception is not a real failure — it is an expected outcome
|
|
90
|
+
# when a reboot resource fires :reboot_now. In that case run_completed
|
|
91
|
+
# has already executed the Compliance Phase, so running it again here
|
|
92
|
+
# would produce a duplicate scan (and the second scan may be killed by
|
|
93
|
+
# the pending reboot).
|
|
94
|
+
if exception.is_a?(Chef::Exceptions::Reboot)
|
|
95
|
+
logger.debug("#{self.class}##{__method__}: skipping Compliance Phase because a reboot was requested")
|
|
96
|
+
return
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Guard against any other code path that might trigger both run_completed
|
|
100
|
+
# and run_failed in the same client run.
|
|
101
|
+
if @compliance_phase_completed
|
|
102
|
+
logger.debug("#{self.class}##{__method__}: skipping Compliance Phase because it has already run in this client run")
|
|
103
|
+
return
|
|
104
|
+
end
|
|
105
|
+
|
|
88
106
|
logger.debug("#{self.class}##{__method__}: enabling Compliance Phase")
|
|
89
107
|
|
|
90
108
|
report_with_interval
|
|
@@ -130,7 +130,7 @@ class Chef
|
|
|
130
130
|
rescue Net::HTTPClientException, Net::HTTPFatalError, Errno::ECONNREFUSED, Timeout::Error, Errno::ETIMEDOUT, SocketError => e
|
|
131
131
|
error_message = "Failed to upload #{file} (#{checksum}) to #{url} : #{e.message}"
|
|
132
132
|
error_message << "\n#{e.response.body}" if e.respond_to?(:response)
|
|
133
|
-
Chef::
|
|
133
|
+
Chef::Log.error(error_message)
|
|
134
134
|
raise
|
|
135
135
|
end
|
|
136
136
|
end
|
|
@@ -24,6 +24,14 @@ class Chef
|
|
|
24
24
|
# when a custom resource uses the 'core::rest_resource' partial.
|
|
25
25
|
#
|
|
26
26
|
module RestResource
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def inherited_accessor(name)
|
|
30
|
+
superclass.public_send(name) if superclass.respond_to?(name)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
public
|
|
34
|
+
|
|
27
35
|
# Define property mapping between resource properties and JSON API fields
|
|
28
36
|
#
|
|
29
37
|
# Maps resource properties to their corresponding locations in the JSON
|
|
@@ -56,12 +64,12 @@ class Chef
|
|
|
56
64
|
# @see #json_to_property Method that uses this mapping to extract values
|
|
57
65
|
# @see #property_to_json Method that uses this mapping to create JSON
|
|
58
66
|
def rest_property_map(rest_property_map = NOT_PASSED)
|
|
59
|
-
|
|
67
|
+
unless rest_property_map.equal?(NOT_PASSED)
|
|
60
68
|
rest_property_map = rest_property_map.to_h { |k| [k.to_sym, k] } if rest_property_map.is_a? Array
|
|
61
69
|
|
|
62
70
|
@rest_property_map = rest_property_map
|
|
63
71
|
end
|
|
64
|
-
@rest_property_map
|
|
72
|
+
@rest_property_map || inherited_accessor(:rest_property_map)
|
|
65
73
|
end
|
|
66
74
|
|
|
67
75
|
# Define the REST API collection URL
|
|
@@ -83,13 +91,13 @@ class Chef
|
|
|
83
91
|
# # GET /api/v1/users # List all users
|
|
84
92
|
# # POST /api/v1/users # Create new user
|
|
85
93
|
def rest_api_collection(rest_api_collection = NOT_PASSED)
|
|
86
|
-
|
|
94
|
+
unless rest_api_collection.equal?(NOT_PASSED)
|
|
87
95
|
raise ArgumentError, "You must pass an absolute path to rest_api_collection" unless rest_api_collection.start_with? "/"
|
|
88
96
|
|
|
89
97
|
@rest_api_collection = rest_api_collection
|
|
90
98
|
end
|
|
91
99
|
|
|
92
|
-
@rest_api_collection
|
|
100
|
+
@rest_api_collection || inherited_accessor(:rest_api_collection)
|
|
93
101
|
end
|
|
94
102
|
|
|
95
103
|
# Define the REST API document URL with RFC 6570 template support
|
|
@@ -131,13 +139,15 @@ class Chef
|
|
|
131
139
|
#
|
|
132
140
|
# @see https://tools.ietf.org/html/rfc6570 RFC 6570 URI Template specification
|
|
133
141
|
def rest_api_document(rest_api_document = NOT_PASSED, first_element_only: false)
|
|
134
|
-
|
|
142
|
+
unless rest_api_document.equal?(NOT_PASSED)
|
|
135
143
|
raise ArgumentError, "You must pass an absolute path to rest_api_document" unless rest_api_document.start_with? "/"
|
|
136
144
|
|
|
137
145
|
@rest_api_document = rest_api_document
|
|
138
146
|
@rest_api_document_first_element_only = first_element_only
|
|
139
147
|
end
|
|
140
|
-
@rest_api_document
|
|
148
|
+
@rest_api_document ||
|
|
149
|
+
inherited_accessor(:rest_api_document) ||
|
|
150
|
+
(rest_api_collection && rest_identity_property ? "#{rest_api_collection}/{#{rest_identity_property}}" : nil)
|
|
141
151
|
end
|
|
142
152
|
|
|
143
153
|
# Define explicit identity mapping for resource identification
|
|
@@ -177,8 +187,8 @@ class Chef
|
|
|
177
187
|
# 'organization.id' => :org_id
|
|
178
188
|
# })
|
|
179
189
|
def rest_identity_map(rest_identity_map = NOT_PASSED)
|
|
180
|
-
@rest_identity_map = rest_identity_map
|
|
181
|
-
@rest_identity_map
|
|
190
|
+
@rest_identity_map = rest_identity_map unless rest_identity_map.equal?(NOT_PASSED)
|
|
191
|
+
@rest_identity_map || inherited_accessor(:rest_identity_map)
|
|
182
192
|
end
|
|
183
193
|
|
|
184
194
|
# Declare properties that should only be sent during resource creation
|
|
@@ -219,17 +229,58 @@ class Chef
|
|
|
219
229
|
# # Initialization parameters
|
|
220
230
|
# rest_post_only_properties [:template_id, :source_snapshot]
|
|
221
231
|
def rest_post_only_properties(rest_post_only_properties = NOT_PASSED)
|
|
222
|
-
|
|
232
|
+
unless rest_post_only_properties.equal?(NOT_PASSED)
|
|
223
233
|
@rest_post_only_properties = Array(rest_post_only_properties).map(&:to_sym)
|
|
224
234
|
end
|
|
225
|
-
@rest_post_only_properties || []
|
|
235
|
+
@rest_post_only_properties || inherited_accessor(:rest_post_only_properties) || []
|
|
226
236
|
end
|
|
227
237
|
|
|
228
238
|
def rest_api_document_first_element_only(rest_api_document_first_element_only = NOT_PASSED)
|
|
229
|
-
|
|
239
|
+
unless rest_api_document_first_element_only.equal?(NOT_PASSED)
|
|
230
240
|
@rest_api_document_first_element_only = rest_api_document_first_element_only
|
|
231
241
|
end
|
|
232
|
-
@rest_api_document_first_element_only
|
|
242
|
+
@rest_api_document_first_element_only || inherited_accessor(:rest_api_document_first_element_only)
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
# Define the base URL for the REST API
|
|
246
|
+
#
|
|
247
|
+
# Sets the base endpoint URL that is prepended to all collection and document
|
|
248
|
+
# URLs. This allows resource definitions to be self-contained without requiring
|
|
249
|
+
# the Train transport endpoint to be pre-configured.
|
|
250
|
+
#
|
|
251
|
+
# @param rest_api_endpoint [String, NOT_PASSED] The base URL of the REST API
|
|
252
|
+
# - NOT_PASSED: Acts as getter, returns current endpoint URL
|
|
253
|
+
#
|
|
254
|
+
# @return [String, nil] The current endpoint URL
|
|
255
|
+
#
|
|
256
|
+
# @example
|
|
257
|
+
# rest_api_endpoint "https://api.example.com"
|
|
258
|
+
# rest_api_collection "/api/v1/users"
|
|
259
|
+
# # GET https://api.example.com/api/v1/users
|
|
260
|
+
def rest_api_endpoint(rest_api_endpoint = NOT_PASSED)
|
|
261
|
+
@rest_api_endpoint = rest_api_endpoint unless rest_api_endpoint.equal?(NOT_PASSED)
|
|
262
|
+
@rest_api_endpoint || inherited_accessor(:rest_api_endpoint)
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
# Declare the property that uniquely identifies a resource in the REST API
|
|
266
|
+
#
|
|
267
|
+
# Sets the identity property for the resource and auto-generates the document
|
|
268
|
+
# URL as "#{rest_api_collection}/{property}" when no explicit rest_api_document
|
|
269
|
+
# is provided. This is a convenience alternative to setting rest_api_document
|
|
270
|
+
# manually.
|
|
271
|
+
#
|
|
272
|
+
# @param property [Symbol, NOT_PASSED] The property name used as the resource identifier
|
|
273
|
+
# - NOT_PASSED: Acts as getter, returns current identity property
|
|
274
|
+
#
|
|
275
|
+
# @return [Symbol, nil] The current identity property name
|
|
276
|
+
#
|
|
277
|
+
# @example
|
|
278
|
+
# rest_api_collection "/api/v1/users"
|
|
279
|
+
# rest_identity_property :username
|
|
280
|
+
# # Auto-generates rest_api_document as "/api/v1/users/{username}"
|
|
281
|
+
def rest_identity_property(property = NOT_PASSED)
|
|
282
|
+
@rest_identity_property = property unless property.equal?(NOT_PASSED)
|
|
283
|
+
@rest_identity_property || inherited_accessor(:rest_identity_property)
|
|
233
284
|
end
|
|
234
285
|
|
|
235
286
|
end
|
|
@@ -33,6 +33,12 @@ class Chef
|
|
|
33
33
|
module ClassMethods
|
|
34
34
|
# We want to mix these in as class methods
|
|
35
35
|
def writable?(path)
|
|
36
|
+
# In target mode the path refers to the remote filesystem. Delegate
|
|
37
|
+
# to TargetIO so the check runs on the remote host via SSH rather than
|
|
38
|
+
# against the local Windows filesystem (where Linux paths like /tmp do
|
|
39
|
+
# not exist and ::File.exist? always returns false).
|
|
40
|
+
return ::TargetIO::File.writable?(path) if Chef::Config.target_mode?
|
|
41
|
+
|
|
36
42
|
::File.exist?(path) && Chef::ReservedNames::Win32::File.file_access_check(
|
|
37
43
|
path, Chef::ReservedNames::Win32::API::Security::FILE_GENERIC_WRITE
|
|
38
44
|
)
|
|
@@ -26,11 +26,13 @@ class Chef
|
|
|
26
26
|
# the values specified by a value object, usually a Chef::Resource.
|
|
27
27
|
class FileAccessControl
|
|
28
28
|
|
|
29
|
+
require_relative "file_access_control/unix"
|
|
30
|
+
|
|
29
31
|
if RUBY_PLATFORM.match?(/mswin|mingw|windows/)
|
|
30
32
|
require_relative "file_access_control/windows"
|
|
33
|
+
|
|
31
34
|
include FileAccessControl::Windows
|
|
32
35
|
else
|
|
33
|
-
require_relative "file_access_control/unix"
|
|
34
36
|
include FileAccessControl::Unix
|
|
35
37
|
end
|
|
36
38
|
|
|
@@ -55,6 +57,15 @@ class Chef
|
|
|
55
57
|
@current_resource, @resource, @provider = current_resource, new_resource, provider
|
|
56
58
|
@file = @current_resource.path
|
|
57
59
|
@modified = false
|
|
60
|
+
|
|
61
|
+
# When running on Windows in target mode the remote host is a Unix
|
|
62
|
+
# system managed via SSH. Extend this instance with the Unix access
|
|
63
|
+
# control module so that permissions are applied via TargetIO
|
|
64
|
+
# (chmod/chown over SSH) rather than Win32 security APIs against a
|
|
65
|
+
# path that does not exist on the local Windows filesystem.
|
|
66
|
+
if RUBY_PLATFORM.match?(/mswin|mingw|windows/) && ChefConfig::Config.target_mode?
|
|
67
|
+
extend FileAccessControl::Unix
|
|
68
|
+
end
|
|
58
69
|
end
|
|
59
70
|
|
|
60
71
|
def modified?
|
|
@@ -30,13 +30,13 @@ class Chef
|
|
|
30
30
|
|
|
31
31
|
def report
|
|
32
32
|
if count == 0
|
|
33
|
-
|
|
33
|
+
Chef::Log.info("No resources to profile")
|
|
34
34
|
return
|
|
35
35
|
end
|
|
36
36
|
|
|
37
37
|
top = all_records.sort_by(&:elapsed_time).last(amount).reverse
|
|
38
38
|
data = top.map { |r| [ r.new_resource.to_s, r.elapsed_time, r.action, r.new_resource.cookbook_name, r.new_resource.recipe_name, stripped_source_line(r.new_resource) ] }
|
|
39
|
-
|
|
39
|
+
Chef::Log.info("Top #{count} slowest #{count == 1 ? "resource" : "resources"}:")
|
|
40
40
|
table = TTY::Table.new(%w{resource elapsed_time action cookbook recipe source}, data)
|
|
41
41
|
rendered = table.render do |renderer|
|
|
42
42
|
renderer.border do
|
|
@@ -44,8 +44,7 @@ class Chef
|
|
|
44
44
|
mid_mid " "
|
|
45
45
|
end
|
|
46
46
|
end
|
|
47
|
-
|
|
48
|
-
puts "\n"
|
|
47
|
+
Chef::Log.info(rendered)
|
|
49
48
|
end
|
|
50
49
|
|
|
51
50
|
def all_records
|
data/lib/chef/licensing.rb
CHANGED
|
@@ -9,12 +9,10 @@ class Chef
|
|
|
9
9
|
class << self
|
|
10
10
|
def fetch_and_persist
|
|
11
11
|
Chef::Log.info "Fetching and persisting license..."
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
|
|
16
|
-
# So for now we skip license validation on Mac, Windows, Linux distributions which run using test kitchen.
|
|
17
|
-
if ENV["TEST_KITCHEN"] && !ChefUtils.docker?
|
|
12
|
+
# Skip license validation in CI/testing environments.
|
|
13
|
+
# This covers GitHub Actions, Buildkite, Test Kitchen, and generic CI.
|
|
14
|
+
# Licensing determination is handled by ChefLicensing directly.
|
|
15
|
+
if skip_license_validation?
|
|
18
16
|
Chef::Log.info "****Skipping license validation..."
|
|
19
17
|
return
|
|
20
18
|
end
|
|
@@ -32,6 +30,12 @@ class Chef
|
|
|
32
30
|
|
|
33
31
|
def check_software_entitlement!
|
|
34
32
|
Chef::Log.info "Checking software entitlement..."
|
|
33
|
+
# Skip entitlement check in the same environments where fetch_and_persist is skipped,
|
|
34
|
+
# since no license keys would have been persisted in those environments.
|
|
35
|
+
if skip_license_validation?
|
|
36
|
+
Chef::Log.info "****Skipping software entitlement check..."
|
|
37
|
+
return
|
|
38
|
+
end
|
|
35
39
|
ChefLicensing.check_software_entitlement!
|
|
36
40
|
rescue ChefLicensing::SoftwareNotEntitled
|
|
37
41
|
Chef::Log.error "License is not entitled to use Chef Infra."
|
|
@@ -97,6 +101,22 @@ class Chef
|
|
|
97
101
|
Chef::Log.error e.message
|
|
98
102
|
Chef::Application.exit! "Usage error", 1 # Generic failure
|
|
99
103
|
end
|
|
104
|
+
|
|
105
|
+
private
|
|
106
|
+
|
|
107
|
+
# Returns true when license validation should be skipped.
|
|
108
|
+
# Skips in CI environments (GitHub Actions, Buildkite, Test Kitchen, generic CI).
|
|
109
|
+
# Does NOT skip when running inside Docker containers managed by Test Kitchen
|
|
110
|
+
# (those are tested separately via chef-test-kitchen-enterprise).
|
|
111
|
+
# CHEF_LICENSE acceptance values are handled by ChefLicensing directly.
|
|
112
|
+
def skip_license_validation?
|
|
113
|
+
ci_environment?
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def ci_environment?
|
|
117
|
+
(ENV["TEST_KITCHEN"] || ENV["GITHUB_ACTIONS"] || ENV["BUILDKITE"] || ENV["CI"]) &&
|
|
118
|
+
!ChefUtils.docker?
|
|
119
|
+
end
|
|
100
120
|
end
|
|
101
121
|
|
|
102
122
|
class EntitlementError < StandardError
|
data/lib/chef/node.rb
CHANGED
|
@@ -650,9 +650,21 @@ class Chef
|
|
|
650
650
|
|
|
651
651
|
# Load a node by name
|
|
652
652
|
def self.load(name)
|
|
653
|
-
from_hash(Chef::ServerAPI.new(Chef::Config[:chef_server_url]
|
|
653
|
+
from_hash(Chef::ServerAPI.new(Chef::Config[:chef_server_url],
|
|
654
|
+
client_name: api_client_name,
|
|
655
|
+
signing_key_filename: api_client_key).get("nodes/#{name}"))
|
|
654
656
|
end
|
|
655
657
|
|
|
658
|
+
def self.api_client_name
|
|
659
|
+
Chef::Config[:api_client_name] || Chef::Config[:node_name]
|
|
660
|
+
end
|
|
661
|
+
private_class_method :api_client_name
|
|
662
|
+
|
|
663
|
+
def self.api_client_key
|
|
664
|
+
Chef::Config[:api_client_key] || Chef::Config[:client_key]
|
|
665
|
+
end
|
|
666
|
+
private_class_method :api_client_key
|
|
667
|
+
|
|
656
668
|
# Remove this node via the REST API
|
|
657
669
|
def destroy
|
|
658
670
|
chef_server_rest.delete("nodes/#{name}")
|
|
@@ -248,13 +248,24 @@ class Chef
|
|
|
248
248
|
end
|
|
249
249
|
|
|
250
250
|
def api_service
|
|
251
|
-
@api_service ||= Chef::ServerAPI.new(config[:chef_server_url],
|
|
251
|
+
@api_service ||= Chef::ServerAPI.new(config[:chef_server_url],
|
|
252
|
+
client_name: api_client_name,
|
|
253
|
+
signing_key_filename: api_client_key,
|
|
254
|
+
version_class: Chef::CookbookManifestVersions)
|
|
252
255
|
end
|
|
253
256
|
|
|
254
257
|
def config
|
|
255
258
|
Chef::Config
|
|
256
259
|
end
|
|
257
260
|
|
|
261
|
+
def api_client_name
|
|
262
|
+
config[:api_client_name] || config[:node_name]
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
def api_client_key
|
|
266
|
+
config[:api_client_key] || config[:client_key]
|
|
267
|
+
end
|
|
268
|
+
|
|
258
269
|
end
|
|
259
270
|
end
|
|
260
271
|
end
|
|
@@ -515,6 +515,8 @@ class Chef
|
|
|
515
515
|
# @api private
|
|
516
516
|
def api_service
|
|
517
517
|
@api_service ||= Chef::ServerAPI.new(config[:chef_server_url],
|
|
518
|
+
client_name: api_client_name,
|
|
519
|
+
signing_key_filename: api_client_key,
|
|
518
520
|
version_class: Chef::CookbookManifestVersions)
|
|
519
521
|
end
|
|
520
522
|
|
|
@@ -523,6 +525,16 @@ class Chef
|
|
|
523
525
|
Chef::Config
|
|
524
526
|
end
|
|
525
527
|
|
|
528
|
+
# @api private
|
|
529
|
+
def api_client_name
|
|
530
|
+
config[:api_client_name] || config[:node_name]
|
|
531
|
+
end
|
|
532
|
+
|
|
533
|
+
# @api private
|
|
534
|
+
def api_client_key
|
|
535
|
+
config[:api_client_key] || config[:client_key]
|
|
536
|
+
end
|
|
537
|
+
|
|
526
538
|
# Indicates whether the policy is temporary, which means an
|
|
527
539
|
# override_runlist was provided. Chef::Client uses this to decide whether
|
|
528
540
|
# to do the final node save at the end of the run or not.
|