chef 17.7.29 → 17.8.25
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/chef/application/base.rb +1 -1
- data/lib/chef/compliance/default_attributes.rb +12 -2
- data/lib/chef/compliance/runner.rb +51 -5
- data/lib/chef/mixin/powershell_exec.rb +6 -5
- data/lib/chef/mixin/why_run.rb +8 -2
- data/lib/chef/powershell.rb +8 -6
- data/lib/chef/provider/mount/linux.rb +16 -2
- data/lib/chef/provider/mount/mount.rb +1 -1
- data/lib/chef/provider/package/dnf.rb +1 -1
- data/lib/chef/provider/package/powershell.rb +13 -10
- data/lib/chef/provider/package/zypper.rb +2 -0
- data/lib/chef/provider/package.rb +58 -23
- data/lib/chef/provider.rb +1 -1
- data/lib/chef/pwsh.rb +3 -2
- data/lib/chef/resource/chef_client_config.rb +22 -1
- data/lib/chef/resource/chef_client_launchd.rb +1 -1
- data/lib/chef/resource/dnf_package.rb +4 -6
- data/lib/chef/resource/dpkg_package.rb +5 -0
- data/lib/chef/resource/execute.rb +1 -4
- data/lib/chef/resource/launchd.rb +0 -3
- data/lib/chef/resource/macos_userdefaults.rb +5 -7
- data/lib/chef/resource/rhsm_register.rb +31 -0
- data/lib/chef/resource/support/client.erb +7 -0
- data/lib/chef/resource/windows_feature_powershell.rb +7 -7
- data/lib/chef/resource.rb +1 -1
- data/lib/chef/version.rb +1 -1
- data/spec/functional/resource/dnf_package_spec.rb +34 -20
- data/spec/functional/resource/dpkg_package_spec.rb +16 -0
- data/spec/functional/resource/macos_userdefaults_spec.rb +20 -0
- data/spec/functional/resource/zypper_package_spec.rb +7 -0
- data/spec/integration/client/client_spec.rb +31 -0
- data/spec/unit/application/base_spec.rb +40 -0
- data/spec/unit/compliance/runner_spec.rb +62 -1
- data/spec/unit/file_access_control_spec.rb +1 -1
- data/spec/unit/mixin/why_run_spec.rb +53 -0
- data/spec/unit/provider/group/groupadd_spec.rb +1 -0
- data/spec/unit/provider/group/usermod_spec.rb +2 -2
- data/spec/unit/provider/ifconfig_spec.rb +2 -0
- data/spec/unit/provider/mount/linux_spec.rb +16 -3
- data/spec/unit/provider/package/bff_spec.rb +1 -0
- data/spec/unit/provider/package/powershell_spec.rb +114 -114
- data/spec/unit/provider/package/rubygems_spec.rb +3 -0
- data/spec/unit/provider/package/solaris_spec.rb +1 -0
- data/spec/unit/provider/service/arch_service_spec.rb +2 -2
- data/spec/unit/provider/service/debian_service_spec.rb +1 -0
- data/spec/unit/provider/service/gentoo_service_spec.rb +1 -0
- data/spec/unit/provider/service/macosx_spec.rb +1 -0
- data/spec/unit/provider/service/redhat_spec.rb +4 -1
- data/spec/unit/provider/service/simple_service_spec.rb +6 -4
- data/spec/unit/provider/user_spec.rb +2 -0
- data/spec/unit/resource/dpkg_package_spec.rb +12 -0
- data/spec/unit/resource/rhsm_register_spec.rb +42 -0
- metadata +9 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ed316b17dc9b7561f86e7eb1200574f7e8946edea8c6e9e48caabe7166b3fff1
|
4
|
+
data.tar.gz: e51295a6e6d7ea03ee3eef0c7f1dcfdc5135567145a9e1317423fe363c5b37d4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 187833c4a2187663915307d01ca12edfabac952728430a651df5c67329b6f0f3c4271f81b840837b7a4a7ae19b6a1aeadb7ac9e4115f082a992e005d1cb7f683
|
7
|
+
data.tar.gz: d89346312b01e97606e0f0ba1e2b9fed0f447700332bcacbcb2843d460f51c3f7348383c0ee8a247ce98decfd7eec36fecda1a2ee7d91203834c75347dc2911e
|
@@ -254,7 +254,7 @@ class Chef::Application::Base < Chef::Application
|
|
254
254
|
short: "-K KEY_FILE",
|
255
255
|
long: "--validation_key KEY_FILE",
|
256
256
|
description: "Set the validation key file location, used for registering new clients.",
|
257
|
-
proc:
|
257
|
+
proc: lambda { |argument| File.expand_path(argument) }
|
258
258
|
|
259
259
|
option :client_key,
|
260
260
|
short: "-k KEY_FILE",
|
@@ -28,7 +28,7 @@ class Chef
|
|
28
28
|
# Controls what is done with the resulting report after the Chef InSpec run.
|
29
29
|
# Accepts a single string value or an array of multiple values.
|
30
30
|
# Accepted values: 'chef-server-automate', 'chef-automate', 'json-file', 'audit-enforcer', 'cli'
|
31
|
-
"reporter" =>
|
31
|
+
"reporter" => nil,
|
32
32
|
|
33
33
|
# Controls if Chef InSpec profiles should be fetched from Chef Automate or Chef Infra Server
|
34
34
|
# in addition to the default fetch locations provided by Chef Inspec.
|
@@ -94,7 +94,17 @@ class Chef
|
|
94
94
|
|
95
95
|
# Should the built-in compliance phase run. True and false force the behavior. Nil does magic based on if you have
|
96
96
|
# profiles defined but do not have the audit cookbook enabled.
|
97
|
-
"compliance_phase" => false
|
97
|
+
"compliance_phase" => false,
|
98
|
+
|
99
|
+
"interval" => {
|
100
|
+
# control how often inspec scans are run, if not on every node converge
|
101
|
+
# notes: false value will result in running inspec scan every converge
|
102
|
+
"enabled" => false,
|
103
|
+
|
104
|
+
# controls how often inspec scans are run (in minutes)
|
105
|
+
# notes: only used if interval is enabled above
|
106
|
+
"time" => 1440,
|
107
|
+
}
|
98
108
|
)
|
99
109
|
end
|
100
110
|
end
|
@@ -71,7 +71,7 @@ class Chef
|
|
71
71
|
|
72
72
|
logger.debug("#{self.class}##{__method__}: enabling Compliance Phase")
|
73
73
|
|
74
|
-
|
74
|
+
report_with_interval
|
75
75
|
end
|
76
76
|
|
77
77
|
def run_failed(_exception, _run_status)
|
@@ -82,7 +82,7 @@ class Chef
|
|
82
82
|
|
83
83
|
logger.debug("#{self.class}##{__method__}: enabling Compliance Phase")
|
84
84
|
|
85
|
-
|
85
|
+
report_with_interval
|
86
86
|
end
|
87
87
|
|
88
88
|
### Below code adapted from audit cookbook's files/default/handler/audit_report.rb
|
@@ -92,7 +92,6 @@ class Chef
|
|
92
92
|
fail_if_not_present
|
93
93
|
inspec_gem_source
|
94
94
|
inspec_version
|
95
|
-
interval
|
96
95
|
owner
|
97
96
|
raise_if_unreachable
|
98
97
|
}.freeze
|
@@ -106,6 +105,15 @@ class Chef
|
|
106
105
|
end
|
107
106
|
end
|
108
107
|
|
108
|
+
def report_with_interval
|
109
|
+
if interval_seconds_left <= 0
|
110
|
+
create_timestamp_file if interval_enabled
|
111
|
+
report
|
112
|
+
else
|
113
|
+
logger.info "Skipping Chef Infra Compliance Phase due to interval settings (next run in #{interval_seconds_left / 60.0} mins)"
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
109
117
|
def report(report = nil)
|
110
118
|
logger.info "Starting Chef Infra Compliance Phase"
|
111
119
|
report ||= generate_report
|
@@ -118,7 +126,7 @@ class Chef
|
|
118
126
|
return
|
119
127
|
end
|
120
128
|
|
121
|
-
|
129
|
+
requested_reporters.each do |reporter_type|
|
122
130
|
logger.info "Reporting to #{reporter_type}"
|
123
131
|
@reporters[reporter_type].send_report(report)
|
124
132
|
end
|
@@ -325,7 +333,7 @@ class Chef
|
|
325
333
|
@reporters = {}
|
326
334
|
# Note that the docs don't say you can use an array, but our implementation
|
327
335
|
# supports it.
|
328
|
-
|
336
|
+
requested_reporters.each do |type|
|
329
337
|
unless SUPPORTED_REPORTERS.include? type
|
330
338
|
raise "CMPL003: '#{type}' found in node['audit']['reporter'] is not a supported reporter for Compliance Phase. Supported reporters are: #{SUPPORTED_REPORTERS.join(", ")}. For more information, see the documentation at https://docs.chef.io/chef_compliance_phase#reporters"
|
331
339
|
end
|
@@ -358,6 +366,44 @@ class Chef
|
|
358
366
|
def safe_input_collection
|
359
367
|
run_context&.input_collection
|
360
368
|
end
|
369
|
+
|
370
|
+
def requested_reporters
|
371
|
+
(Array(node["audit"]["reporter"]) + ["cli"]).uniq
|
372
|
+
end
|
373
|
+
|
374
|
+
def create_timestamp_file
|
375
|
+
FileUtils.touch report_timing_file
|
376
|
+
end
|
377
|
+
|
378
|
+
def report_timing_file
|
379
|
+
::File.join(Chef::FileCache.create_cache_path("compliance"), "report_timing.json")
|
380
|
+
end
|
381
|
+
|
382
|
+
def interval_time
|
383
|
+
@interval_time ||= node.read("audit", "interval", "time")
|
384
|
+
end
|
385
|
+
|
386
|
+
def interval_enabled
|
387
|
+
@interval_enabled ||= node.read("audit", "interval", "enabled")
|
388
|
+
end
|
389
|
+
|
390
|
+
def interval_seconds
|
391
|
+
@interval_seconds ||=
|
392
|
+
if interval_enabled
|
393
|
+
logger.debug "Running Chef Infra Compliance Phase every #{interval_time} minutes"
|
394
|
+
interval_time * 60
|
395
|
+
else
|
396
|
+
logger.debug "Running Chef Infra Compliance Phase on every run"
|
397
|
+
0
|
398
|
+
end
|
399
|
+
end
|
400
|
+
|
401
|
+
def interval_seconds_left
|
402
|
+
return 0 unless ::File.exist?(report_timing_file)
|
403
|
+
|
404
|
+
seconds_since_last_run = Time.now - ::File.mtime(report_timing_file)
|
405
|
+
interval_seconds - seconds_since_last_run
|
406
|
+
end
|
361
407
|
end
|
362
408
|
end
|
363
409
|
end
|
@@ -104,13 +104,14 @@ class Chef
|
|
104
104
|
#
|
105
105
|
# @param script [String] script to run
|
106
106
|
# @param interpreter [Symbol] the interpreter type, `:powershell` or `:pwsh`
|
107
|
+
# @param timeout [Integer, nil] timeout in seconds.
|
107
108
|
# @return [Chef::PowerShell] output
|
108
|
-
def powershell_exec(script, interpreter = :powershell)
|
109
|
+
def powershell_exec(script, interpreter = :powershell, timeout: -1)
|
109
110
|
case interpreter
|
110
111
|
when :powershell
|
111
|
-
Chef::PowerShell.new(script)
|
112
|
+
Chef::PowerShell.new(script, timeout: timeout)
|
112
113
|
when :pwsh
|
113
|
-
Chef::Pwsh.new(script)
|
114
|
+
Chef::Pwsh.new(script, timeout: timeout)
|
114
115
|
else
|
115
116
|
raise ArgumentError, "Expected interpreter of :powershell or :pwsh"
|
116
117
|
end
|
@@ -118,8 +119,8 @@ class Chef
|
|
118
119
|
|
119
120
|
# The same as the #powershell_exec method except this will raise
|
120
121
|
# Chef::PowerShell::CommandFailed if the command fails
|
121
|
-
def powershell_exec!(script, interpreter = :powershell)
|
122
|
-
cmd = powershell_exec(script, interpreter)
|
122
|
+
def powershell_exec!(script, interpreter = :powershell, **options)
|
123
|
+
cmd = powershell_exec(script, interpreter, **options)
|
123
124
|
cmd.error!
|
124
125
|
cmd
|
125
126
|
end
|
data/lib/chef/mixin/why_run.rb
CHANGED
@@ -242,8 +242,12 @@ class Chef
|
|
242
242
|
end
|
243
243
|
end
|
244
244
|
|
245
|
-
|
246
|
-
|
245
|
+
attr_accessor :action
|
246
|
+
|
247
|
+
def initialize(resource, run_context, action)
|
248
|
+
@resource = resource
|
249
|
+
@run_context = run_context
|
250
|
+
@action = action
|
247
251
|
@assertions = Hash.new { |h, k| h[k] = [] }
|
248
252
|
@blocked_actions = []
|
249
253
|
end
|
@@ -305,6 +309,8 @@ class Chef
|
|
305
309
|
# "You don't have sufficient privileges to delete #{@new_resource.path}")
|
306
310
|
# end
|
307
311
|
def assert(*actions)
|
312
|
+
return unless actions.include?(action.to_sym) || actions.include?(:all_actions)
|
313
|
+
|
308
314
|
assertion = Assertion.new
|
309
315
|
yield assertion
|
310
316
|
actions.each { |action| @assertions[action] << assertion }
|
data/lib/chef/powershell.rb
CHANGED
@@ -33,15 +33,16 @@ class Chef
|
|
33
33
|
# Requires: .NET Framework 4.0 or higher on the target machine.
|
34
34
|
#
|
35
35
|
# @param script [String] script to run
|
36
|
+
# @param timeout [Integer, nil] timeout in seconds.
|
36
37
|
# @return [Object] output
|
37
|
-
def initialize(script)
|
38
|
+
def initialize(script, timeout: -1)
|
38
39
|
# This Powershell DLL source lives here: https://github.com/chef/chef-powershell-shim
|
39
40
|
# Every merge into that repo triggers a Habitat build and promotion. Running
|
40
41
|
# the rake :update_chef_exec_dll task in this (chef/chef) repo will pull down
|
41
42
|
# the built packages and copy the binaries to distro/ruby_bin_folder. Bundle install
|
42
43
|
# ensures that the correct architecture binaries are installed into the path.
|
43
44
|
@dll ||= "Chef.PowerShell.Wrapper.dll"
|
44
|
-
exec(script)
|
45
|
+
exec(script, timeout: timeout)
|
45
46
|
end
|
46
47
|
|
47
48
|
#
|
@@ -64,12 +65,13 @@ class Chef
|
|
64
65
|
raise Chef::PowerShell::CommandFailed, "Unexpected exit in PowerShell command: #{@errors}" if error?
|
65
66
|
end
|
66
67
|
|
67
|
-
|
68
|
+
private
|
68
69
|
|
69
|
-
def exec(script)
|
70
|
+
def exec(script, timeout: -1)
|
70
71
|
FFI.ffi_lib @dll
|
71
|
-
FFI.attach_function :execute_powershell, :ExecuteScript,
|
72
|
-
|
72
|
+
FFI.attach_function :execute_powershell, :ExecuteScript, %i{string int}, :pointer
|
73
|
+
timeout = -1 if timeout == 0 || timeout.nil?
|
74
|
+
execution = FFI.execute_powershell(script, timeout).read_utf16string
|
73
75
|
hashed_outcome = Chef::JSONCompat.parse(execution)
|
74
76
|
@result = Chef::JSONCompat.parse(hashed_outcome["result"])
|
75
77
|
@errors = hashed_outcome["errors"]
|
@@ -29,10 +29,16 @@ class Chef
|
|
29
29
|
# "findmnt" outputs the mount points with volume.
|
30
30
|
# Convert the mount_point of the resource to a real path in case it
|
31
31
|
# contains symlinks in its parents dirs.
|
32
|
+
def loop_mount_points
|
33
|
+
# get loop_mount_points only if not initialized earlier
|
34
|
+
@loop_mount_points ||= shell_out!("losetup -a").stdout
|
35
|
+
|
36
|
+
rescue Errno::ENOENT
|
37
|
+
@loop_mount_points = ""
|
38
|
+
end
|
32
39
|
|
33
40
|
def mounted?
|
34
41
|
mounted = false
|
35
|
-
|
36
42
|
real_mount_point = if ::File.exists? @new_resource.mount_point
|
37
43
|
::File.realpath(@new_resource.mount_point)
|
38
44
|
else
|
@@ -45,6 +51,14 @@ class Chef
|
|
45
51
|
when /\A#{Regexp.escape(real_mount_point)}\s+#{device_mount_regex}\s/
|
46
52
|
mounted = true
|
47
53
|
logger.trace("Special device #{device_logstring} mounted as #{real_mount_point}")
|
54
|
+
# Permalink for loop type devices mount points https://rubular.com/r/a0bS4p2RvXsGxx
|
55
|
+
when %r{\A#{Regexp.escape(real_mount_point)}\s+\/dev\/loop+[0-9]+\s}
|
56
|
+
loop_mount_points.each_line do |mount_point|
|
57
|
+
if mount_point.include? device_real
|
58
|
+
mounted = true
|
59
|
+
break
|
60
|
+
end
|
61
|
+
end
|
48
62
|
# Permalink for multiple devices mounted to the same mount point(i.e. '/proc') https://rubular.com/r/a356yzspU7N9TY
|
49
63
|
when %r{\A#{Regexp.escape(real_mount_point)}\s+([/\w])+\s}
|
50
64
|
mounted = false
|
@@ -64,4 +78,4 @@ class Chef
|
|
64
78
|
end
|
65
79
|
end
|
66
80
|
end
|
67
|
-
end
|
81
|
+
end
|
@@ -17,13 +17,13 @@
|
|
17
17
|
|
18
18
|
require_relative "../package"
|
19
19
|
require_relative "../../resource/powershell_package"
|
20
|
-
require_relative "../../mixin/
|
20
|
+
require_relative "../../mixin/powershell_exec"
|
21
21
|
|
22
22
|
class Chef
|
23
23
|
class Provider
|
24
24
|
class Package
|
25
25
|
class Powershell < Chef::Provider::Package
|
26
|
-
include Chef::Mixin::
|
26
|
+
include Chef::Mixin::PowershellExec
|
27
27
|
|
28
28
|
provides :powershell_package
|
29
29
|
|
@@ -54,9 +54,9 @@ class Chef
|
|
54
54
|
# Installs the package specified with the version passed else latest version will be installed
|
55
55
|
def install_package(names, versions)
|
56
56
|
names.each_with_index do |name, index|
|
57
|
-
cmd =
|
57
|
+
cmd = powershell_exec(build_powershell_package_command("Install-Package '#{name}'", versions[index]), timeout: new_resource.timeout)
|
58
58
|
next if cmd.nil?
|
59
|
-
raise Chef::Exceptions::PowershellCmdletException, "Failed to install package due to catalog signing error, use skip_publisher_check to force install" if /SkipPublisherCheck/.match?(cmd.
|
59
|
+
raise Chef::Exceptions::PowershellCmdletException, "Failed to install package due to catalog signing error, use skip_publisher_check to force install" if /SkipPublisherCheck/.match?(cmd.error)
|
60
60
|
end
|
61
61
|
end
|
62
62
|
|
@@ -64,11 +64,12 @@ class Chef
|
|
64
64
|
def remove_package(names, versions)
|
65
65
|
names.each_with_index do |name, index|
|
66
66
|
if versions && !versions[index].nil?
|
67
|
-
|
67
|
+
powershell_exec(build_powershell_package_command("Uninstall-Package '#{name}'", versions[index]), timeout: new_resource.timeout)
|
68
68
|
else
|
69
69
|
version = "0"
|
70
70
|
until version.empty?
|
71
|
-
version =
|
71
|
+
version = powershell_exec(build_powershell_package_command("Uninstall-Package '#{name}'"), timeout: new_resource.timeout).result
|
72
|
+
version = version.strip if version.respond_to?(:strip)
|
72
73
|
unless version.empty?
|
73
74
|
logger.info("Removed package '#{name}' with version #{version}")
|
74
75
|
end
|
@@ -82,13 +83,14 @@ class Chef
|
|
82
83
|
versions = []
|
83
84
|
new_resource.package_name.each_with_index do |name, index|
|
84
85
|
version = if new_resource.version && !new_resource.version[index].nil?
|
85
|
-
|
86
|
+
powershell_exec(build_powershell_package_command("Find-Package '#{name}'", new_resource.version[index]), timeout: new_resource.timeout).result
|
86
87
|
else
|
87
|
-
|
88
|
+
powershell_exec(build_powershell_package_command("Find-Package '#{name}'"), timeout: new_resource.timeout).result
|
88
89
|
end
|
89
90
|
if version.empty?
|
90
91
|
version = nil
|
91
92
|
end
|
93
|
+
version = version.strip if version.respond_to?(:strip)
|
92
94
|
versions.push(version)
|
93
95
|
end
|
94
96
|
versions
|
@@ -99,13 +101,14 @@ class Chef
|
|
99
101
|
version_list = []
|
100
102
|
new_resource.package_name.each_with_index do |name, index|
|
101
103
|
version = if new_resource.version && !new_resource.version[index].nil?
|
102
|
-
|
104
|
+
powershell_exec(build_powershell_package_command("Get-Package '#{name}'", new_resource.version[index]), timeout: new_resource.timeout).result
|
103
105
|
else
|
104
|
-
|
106
|
+
powershell_exec(build_powershell_package_command("Get-Package '#{name}'"), timeout: new_resource.timeout).result
|
105
107
|
end
|
106
108
|
if version.empty?
|
107
109
|
version = nil
|
108
110
|
end
|
111
|
+
version = version.strip if version.respond_to?(:strip)
|
109
112
|
version_list.push(version)
|
110
113
|
end
|
111
114
|
version_list
|
@@ -438,47 +438,81 @@ class Chef
|
|
438
438
|
@target_version_array ||=
|
439
439
|
begin
|
440
440
|
target_version_array = []
|
441
|
-
each_package do |package_name, new_version, current_version, candidate_version|
|
441
|
+
each_package do |package_name, new_version, current_version, candidate_version, magic_version|
|
442
442
|
case action
|
443
443
|
when :upgrade
|
444
|
-
if current_version
|
445
|
-
#
|
446
|
-
#
|
444
|
+
if version_equals?(current_version, new_version)
|
445
|
+
# This is a short-circuit (mostly for the rubygems provider) to avoid needing to
|
446
|
+
# expensively query the candidate_version which must come later. This only checks
|
447
|
+
# exact matching, the check for fuzzy matching is later.
|
448
|
+
logger.trace("#{new_resource} #{package_name} #{new_version} is already installed")
|
449
|
+
target_version_array.push(nil)
|
450
|
+
elsif current_version.nil?
|
451
|
+
# This is a simple check to see if we have any currently installed version at all, this is
|
452
|
+
# safe to do before the allow_downgrade check so we check this before.
|
447
453
|
logger.trace("#{new_resource} has no existing installed version. Installing install #{candidate_version}")
|
448
454
|
target_version_array.push(candidate_version)
|
449
|
-
elsif !
|
450
|
-
#
|
451
|
-
|
455
|
+
elsif !allow_downgrade && version_compare(current_version, candidate_version) == 1
|
456
|
+
# This check for downgrading when allow_downgrade is false uses the current_version rather
|
457
|
+
# than the magic_version since we never want to downgrade even if the constraints are not met
|
458
|
+
# if the version is higher. This check does use the candidate_version and unlazies this so
|
459
|
+
# there will a perf hit on idempotent use when allow_downgrade is false which is unavoidable.
|
460
|
+
logger.trace("#{new_resource} #{package_name} has installed version #{current_version}, which is newer than available version #{candidate_version}. Skipping...)")
|
452
461
|
target_version_array.push(nil)
|
462
|
+
elsif magic_version.nil?
|
463
|
+
# This is the check for fuzzy matching of the installed_version, where if the installed version
|
464
|
+
# does not match the desired version constraints (but is not an exact match) then we need to
|
465
|
+
# install the candidate_version (this must come after the allow_downgrade check)
|
466
|
+
logger.trace("#{new_resource} has an installed version that does not match the version constraint. Installing install #{candidate_version}")
|
467
|
+
target_version_array.push(candidate_version)
|
453
468
|
elsif candidate_version.nil?
|
469
|
+
# This check necessarily unlazies the candidate_version and may be expensive (connecting to
|
470
|
+
# rubygems.org or whatever). It comes as late as possible.
|
454
471
|
logger.trace("#{new_resource} #{package_name} has no candidate_version to upgrade to")
|
455
472
|
target_version_array.push(nil)
|
456
473
|
elsif version_equals?(current_version, candidate_version)
|
474
|
+
# This check sees if the candidate_version is already installed or if we should upgrade/update the
|
475
|
+
# package. This is the normal idempotent behavior of :upgrade and is inherently expensive due to
|
476
|
+
# unlazying the candidate_version. To prevent the perf hit the version may be specified with a full
|
477
|
+
# version constraint. Then the cookbook can roll the version forward and use :upgrade to force version
|
478
|
+
# pinning.
|
457
479
|
logger.trace("#{new_resource} #{package_name} #{candidate_version} is already installed")
|
458
480
|
target_version_array.push(nil)
|
459
|
-
elsif !allow_downgrade && version_compare(current_version, candidate_version) == 1
|
460
|
-
logger.trace("#{new_resource} #{package_name} has installed version #{current_version}, which is newer than available version #{candidate_version}. Skipping...)")
|
461
|
-
target_version_array.push(nil)
|
462
481
|
else
|
463
|
-
logger.trace("#{new_resource} #{package_name} is out of date, will
|
482
|
+
logger.trace("#{new_resource} #{package_name} is out of date, will update to #{candidate_version}")
|
464
483
|
target_version_array.push(candidate_version)
|
465
484
|
end
|
466
485
|
|
467
486
|
when :install
|
468
|
-
if new_version && !
|
487
|
+
if current_version && new_version && !allow_downgrade && version_compare(current_version, new_version) == 1
|
488
|
+
# This is the idempotency guard for downgrades when downgrades are not allowed. This should perhaps raise
|
489
|
+
# an exception since we were told to install an exact package version but we are silently refusing to do so
|
490
|
+
# because a higher version is already installed. Maybe we need a flag for users to apply their preferred
|
491
|
+
# declarative philosophy? This has to come early and outside of the two code paths below.
|
492
|
+
logger.warn("#{new_resource} #{package_name} has installed version #{current_version}, which is newer than available version #{new_version}. Skipping...)")
|
493
|
+
target_version_array.push(nil)
|
494
|
+
elsif new_version && !use_magic_version?
|
495
|
+
# This is for "non magic version using" subclasses to do comparisons between the current_version and the
|
496
|
+
# desired new_version. XXX: If we converted this to current_version_requirement_satisfied? and made it specific
|
497
|
+
# to the current version check and then eliminated the magic_version, we might be able to eliminate separate codepaths
|
498
|
+
# here, and eliminate the semantic confusion around the magic_version?
|
469
499
|
if version_requirement_satisfied?(current_version, new_version)
|
470
500
|
logger.trace("#{new_resource} #{package_name} #{current_version} satisfies #{new_version} requirement")
|
471
501
|
target_version_array.push(nil)
|
472
|
-
elsif current_version && !allow_downgrade && version_compare(current_version, new_version) == 1
|
473
|
-
logger.warn("#{new_resource} #{package_name} has installed version #{current_version}, which is newer than available version #{new_version}. Skipping...)")
|
474
|
-
target_version_array.push(nil)
|
475
502
|
else
|
503
|
+
# XXX: some subclasses seem to depend on this behavior where the new_version can be different from the
|
504
|
+
# candidate_version and we install the new_version, it seems like the candidate_version should be fixed to
|
505
|
+
# be resolved correctly to the new_version for those providers. although it may just be unit test bugs.
|
506
|
+
# it would be more correct to use the candidate_version here, but then it needs to be the correctly resolved
|
507
|
+
# candidate_version against the new_version constraint.
|
476
508
|
logger.trace("#{new_resource} #{package_name} #{current_version} needs updating to #{new_version}")
|
477
509
|
target_version_array.push(new_version)
|
478
510
|
end
|
479
|
-
elsif
|
480
|
-
#
|
481
|
-
#
|
511
|
+
elsif magic_version.nil?
|
512
|
+
# This is for when we have a "magic version using" subclass and where the installed version does not match the
|
513
|
+
# constraint specified in the new_version, so we need to upgrade to the candidate_version. This is the only
|
514
|
+
# codepath in the :install branch which references the candidate_version so it is slow, but it is the path where
|
515
|
+
# we need to do work anyway. XXX: should we check for candidate_version.nil? somewhere around here?
|
482
516
|
logger.trace("#{new_resource} #{package_name} not installed, installing #{candidate_version}")
|
483
517
|
target_version_array.push(candidate_version)
|
484
518
|
else
|
@@ -512,8 +546,8 @@ class Chef
|
|
512
546
|
@packages_missing_candidates ||=
|
513
547
|
begin
|
514
548
|
missing = []
|
515
|
-
each_package do |package_name, new_version, current_version, candidate_version|
|
516
|
-
missing.push(package_name) if
|
549
|
+
each_package do |package_name, new_version, current_version, candidate_version, magic_version|
|
550
|
+
missing.push(package_name) if magic_version.nil? && candidate_version.nil?
|
517
551
|
end
|
518
552
|
missing
|
519
553
|
end
|
@@ -536,7 +570,7 @@ class Chef
|
|
536
570
|
@forced_packages_missing_candidates ||=
|
537
571
|
begin
|
538
572
|
missing = []
|
539
|
-
each_package do |package_name, new_version, current_version, candidate_version|
|
573
|
+
each_package do |package_name, new_version, current_version, candidate_version, magic_version|
|
540
574
|
next if new_version.nil? || current_version.nil?
|
541
575
|
|
542
576
|
if use_magic_version?
|
@@ -559,9 +593,10 @@ class Chef
|
|
559
593
|
def each_package
|
560
594
|
package_name_array.each_with_index do |package_name, i|
|
561
595
|
candidate_version = candidate_version_array[i]
|
562
|
-
current_version =
|
596
|
+
current_version = current_version_array[i]
|
597
|
+
magic_version = use_magic_version? ? magic_version_array[i] : current_version_array[i]
|
563
598
|
new_version = new_version_array[i]
|
564
|
-
yield package_name, new_version, current_version, candidate_version
|
599
|
+
yield package_name, new_version, current_version, candidate_version, magic_version
|
565
600
|
end
|
566
601
|
end
|
567
602
|
|
data/lib/chef/provider.rb
CHANGED
@@ -269,7 +269,7 @@ class Chef
|
|
269
269
|
end
|
270
270
|
|
271
271
|
def requirements
|
272
|
-
@requirements ||= ResourceRequirements.new(@new_resource, run_context)
|
272
|
+
@requirements ||= ResourceRequirements.new(@new_resource, run_context, action || new_resource.action)
|
273
273
|
end
|
274
274
|
|
275
275
|
def description(description = "NOT_PASSED")
|
data/lib/chef/pwsh.rb
CHANGED
@@ -24,15 +24,16 @@ class Chef
|
|
24
24
|
# bindir directory.
|
25
25
|
#
|
26
26
|
# @param script [String] script to run
|
27
|
+
# @param timeout [Integer, nil] timeout in seconds.
|
27
28
|
# @return [Object] output
|
28
|
-
def initialize(script)
|
29
|
+
def initialize(script, timeout: -1)
|
29
30
|
@dll = Pwsh.dll
|
30
31
|
super
|
31
32
|
end
|
32
33
|
|
33
34
|
protected
|
34
35
|
|
35
|
-
def exec(script)
|
36
|
+
def exec(script, timeout: -1)
|
36
37
|
# Note that we need to override the location of the shared dotnet core library
|
37
38
|
# location. With most .net core applications, you can simply publish them as a
|
38
39
|
# "self-contained" application allowing consumers of the application to run them
|
@@ -87,6 +87,17 @@ class Chef
|
|
87
87
|
]
|
88
88
|
end
|
89
89
|
```
|
90
|
+
|
91
|
+
**Report directly to the [Chef Automate data collector endpoint](/automate/data_collection/#configure-chef-infra-client-to-use-the-data-collector-endpoint-in-chef-automate).**
|
92
|
+
|
93
|
+
```ruby
|
94
|
+
chef_client_config 'Create client.rb' do
|
95
|
+
chef_server_url 'https://chef.example.dmz'
|
96
|
+
data_collector_server_url 'https://automate.example.dmz'
|
97
|
+
data_collector_token 'TEST_TOKEN_TEST'
|
98
|
+
end
|
99
|
+
```
|
100
|
+
|
90
101
|
DOC
|
91
102
|
|
92
103
|
# @todo policy_file or policy_group being set requires the other to be set so enforce that.
|
@@ -231,6 +242,14 @@ class Chef
|
|
231
242
|
property :additional_config, String,
|
232
243
|
description: "Additional text to add at the bottom of the client.rb config. This can be used to run custom Ruby or to add less common config options"
|
233
244
|
|
245
|
+
property :data_collector_server_url, String,
|
246
|
+
description: "The data collector url (typically automate) to send node, converge and compliance data. Note: Data collection reporting to Automate should be performed directly by Chef Infra Server if possible, as this removes the need to distribute tokens to individual nodes.",
|
247
|
+
introduced: "17.8"
|
248
|
+
|
249
|
+
property :data_collector_token, String,
|
250
|
+
description: "The data collector token to interact with the data collector server url (Automate). Note: Data collection reporting to Automate should be performed directly by Chef Infra Server if possible, as this removes the need to distribute tokens to individual nodes.",
|
251
|
+
introduced: "17.8"
|
252
|
+
|
234
253
|
action :create, description: "Create a client.rb config file for configuring #{ChefUtils::Dist::Infra::PRODUCT}." do
|
235
254
|
unless ::Dir.exist?(new_resource.config_directory)
|
236
255
|
directory new_resource.config_directory do
|
@@ -282,7 +301,9 @@ class Chef
|
|
282
301
|
ssl_verify_mode: new_resource.ssl_verify_mode,
|
283
302
|
start_handlers: format_handler(new_resource.start_handlers),
|
284
303
|
additional_config: new_resource.additional_config,
|
285
|
-
policy_persist_run_list: new_resource.policy_persist_run_list
|
304
|
+
policy_persist_run_list: new_resource.policy_persist_run_list,
|
305
|
+
data_collector_server_url: new_resource.data_collector_server_url,
|
306
|
+
data_collector_token: new_resource.data_collector_token
|
286
307
|
)
|
287
308
|
mode "0640"
|
288
309
|
action :create
|
@@ -134,7 +134,7 @@ class Chef
|
|
134
134
|
standard_error_path ::File.join(new_resource.log_directory, new_resource.log_file_name)
|
135
135
|
program_arguments ["/bin/bash",
|
136
136
|
"-c",
|
137
|
-
"echo; echo #{ChefUtils::Dist::Infra::PRODUCT} launchd daemon config has been updated. Manually unloading and reloading the daemon; echo Now unloading the daemon; /bin/launchctl unload /Library/LaunchDaemons/com.#{ChefUtils::Dist::Infra::SHORT}.#{ChefUtils::Dist::Infra::CLIENT}.plist; sleep 2; echo Now loading the daemon; /bin/launchctl load /Library/LaunchDaemons/com.#{ChefUtils::Dist::Infra::SHORT}.#{ChefUtils::Dist::Infra::CLIENT}.plist"]
|
137
|
+
"echo; echo #{ChefUtils::Dist::Infra::PRODUCT} launchd daemon config has been updated. Manually unloading and reloading the daemon; echo Now unloading the daemon; sudo /bin/launchctl unload /Library/LaunchDaemons/com.#{ChefUtils::Dist::Infra::SHORT}.#{ChefUtils::Dist::Infra::CLIENT}.plist; sleep 2; echo Now loading the daemon; sudo /bin/launchctl load /Library/LaunchDaemons/com.#{ChefUtils::Dist::Infra::SHORT}.#{ChefUtils::Dist::Infra::CLIENT}.plist"]
|
138
138
|
action :enable # enable creates the plist & triggers service restarts on change
|
139
139
|
end
|
140
140
|
|
@@ -68,12 +68,10 @@ class Chef
|
|
68
68
|
end
|
69
69
|
}
|
70
70
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
true
|
76
|
-
end
|
71
|
+
property :allow_downgrade, [ TrueClass, FalseClass ],
|
72
|
+
description: "Allow downgrading a package to satisfy requested version requirements.",
|
73
|
+
default: true,
|
74
|
+
desired_state: false
|
77
75
|
end
|
78
76
|
end
|
79
77
|
end
|
@@ -37,6 +37,11 @@ class Chef
|
|
37
37
|
property :response_file_variables, Hash,
|
38
38
|
description: "A Hash of response file variables in the form of {'VARIABLE' => 'VALUE'}.",
|
39
39
|
default: {}, desired_state: false
|
40
|
+
|
41
|
+
property :allow_downgrade, [ TrueClass, FalseClass ],
|
42
|
+
description: "Allow downgrading a package to satisfy requested version requirements.",
|
43
|
+
default: true,
|
44
|
+
desired_state: false
|
40
45
|
end
|
41
46
|
end
|
42
47
|
end
|