chef 16.9.16-universal-mingw32 → 16.10.8-universal-mingw32
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +3 -0
- data/chef-universal-mingw32.gemspec +1 -1
- data/chef.gemspec +10 -1
- data/lib/chef/compliance/runner.rb +6 -8
- data/lib/chef/dsl/reboot_pending.rb +1 -1
- data/lib/chef/file_access_control/windows.rb +4 -4
- data/lib/chef/file_cache.rb +4 -4
- data/lib/chef/formatters/error_inspectors/resource_failure_inspector.rb +1 -1
- data/lib/chef/handler/json_file.rb +1 -1
- data/lib/chef/knife/bootstrap.rb +54 -4
- data/lib/chef/provider/package.rb +2 -2
- data/lib/chef/provider/package/dnf/dnf_helper.py +1 -1
- data/lib/chef/provider/package/freebsd/pkgng.rb +3 -1
- data/lib/chef/resource.rb +27 -3
- data/lib/chef/resource/windows_certificate.rb +47 -17
- data/lib/chef/resource_inspector.rb +5 -1
- data/lib/chef/shell.rb +32 -1
- data/lib/chef/util/dsc/configuration_generator.rb +1 -1
- data/lib/chef/version.rb +1 -1
- data/lib/chef/version_string.rb +1 -1
- data/spec/functional/resource/ohai_spec.rb +2 -10
- data/spec/integration/recipes/resource_action_spec.rb +14 -0
- data/spec/spec_helper.rb +1 -1
- data/spec/unit/compliance/runner_spec.rb +5 -7
- data/spec/unit/dsl/reboot_pending_spec.rb +2 -2
- data/spec/unit/formatters/error_inspectors/resource_failure_inspector_spec.rb +2 -2
- data/spec/unit/knife/bootstrap_spec.rb +42 -3
- data/spec/unit/knife/supermarket_share_spec.rb +5 -6
- data/spec/unit/provider/package/dnf/python_helper_spec.rb +7 -1
- data/spec/unit/provider/package/freebsd/pkgng_spec.rb +1 -1
- data/spec/unit/resource_inspector_spec.rb +7 -2
- data/spec/unit/resource_spec.rb +46 -0
- metadata +16 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f1d6650e44387969be09051f429c75ad68040bd28289d003f0ae9dde1166f8f7
|
4
|
+
data.tar.gz: af13e87700fabfa6481fb52b9ead99980586fdbcee51d0c44f4bd24d7534fcdc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7da2206957b65f0bab0ad438c6f71e9472362d1b05fbaf359b31949f546c8a6afb937e59ca72c3e02330f1dc6674c340a029c2a3236e78a19f2571b2183cba70
|
7
|
+
data.tar.gz: a4025c073d6d9dfcbf03110fb98475edbe9a4a6cb798ff81111b02e45ba5b4b2659fdb4a916d22c0f70bbdc9c57e532eeb79c4eadc3db15c84ef8f98e6886ab9
|
data/Gemfile
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
source "https://rubygems.org"
|
2
2
|
|
3
|
+
# pin until issues with Windows builds in 1.14.2 are resolved
|
4
|
+
gem "ffi", "=1.13.1"
|
5
|
+
|
3
6
|
# Note we do not use the gemspec DSL which restricts to the
|
4
7
|
# gemspec for the current platform and filters out other platforms
|
5
8
|
# during a bundle lock operation. We actually want dependencies from
|
@@ -14,7 +14,7 @@ gemspec.add_dependency "win32-service", ">= 2.1.5", "< 3.0"
|
|
14
14
|
gemspec.add_dependency "wmi-lite", "~> 1.0"
|
15
15
|
gemspec.add_dependency "win32-taskscheduler", "~> 2.0"
|
16
16
|
gemspec.add_dependency "iso8601", ">= 0.12.1", "< 0.14" # validate 0.14 when it comes out
|
17
|
-
gemspec.add_dependency "win32-certstore", "~> 0.
|
17
|
+
gemspec.add_dependency "win32-certstore", "~> 0.5" # 0.5+ required for specifying user vs. system store
|
18
18
|
gemspec.extensions << "ext/win32-eventlog/Rakefile"
|
19
19
|
gemspec.files += Dir.glob("{distro,ext}/**/*")
|
20
20
|
|
data/chef.gemspec
CHANGED
@@ -1,4 +1,13 @@
|
|
1
1
|
$:.unshift(File.dirname(__FILE__) + "/lib")
|
2
|
+
vs_path = File.expand_path("chef-utils/lib/chef-utils/version_string.rb", __dir__)
|
3
|
+
|
4
|
+
if File.exist?(vs_path)
|
5
|
+
# this is the moral equivalent of a require_relative since bundler makes require_relative here fail hard
|
6
|
+
eval(IO.read(vs_path))
|
7
|
+
else
|
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"
|
10
|
+
end
|
2
11
|
require "chef/version"
|
3
12
|
|
4
13
|
Gem::Specification.new do |s|
|
@@ -51,7 +60,7 @@ Gem::Specification.new do |s|
|
|
51
60
|
s.add_dependency "iniparse", "~> 1.4"
|
52
61
|
s.add_dependency "addressable"
|
53
62
|
s.add_dependency "syslog-logger", "~> 1.6"
|
54
|
-
s.add_dependency "uuidtools", "
|
63
|
+
s.add_dependency "uuidtools", ">= 2.1.5", "< 3.0"
|
55
64
|
|
56
65
|
s.add_dependency "proxifier", "~> 1.0"
|
57
66
|
|
@@ -11,15 +11,17 @@ class Chef
|
|
11
11
|
class Runner < EventDispatch::Base
|
12
12
|
extend Forwardable
|
13
13
|
|
14
|
-
attr_accessor :run_id
|
14
|
+
attr_accessor :run_id
|
15
15
|
attr_reader :node
|
16
16
|
def_delegators :node, :logger
|
17
17
|
|
18
18
|
def enabled?
|
19
|
-
|
19
|
+
# Did we parse the libraries file from the audit cookbook? This class dates back to when Chef Automate was
|
20
|
+
# renamed from Chef Visibility in 2017, so should capture all modern versions of the audit cookbook.
|
21
|
+
audit_cookbook_present = defined?(::Reporter::ChefAutomate)
|
20
22
|
|
21
|
-
logger.
|
22
|
-
logger.
|
23
|
+
logger.debug("#{self.class}##{__method__}: #{Inspec::Dist::PRODUCT_NAME} profiles? #{inspec_profiles.any?}")
|
24
|
+
logger.debug("#{self.class}##{__method__}: audit cookbook? #{audit_cookbook_present}")
|
23
25
|
|
24
26
|
inspec_profiles.any? && !audit_cookbook_present
|
25
27
|
end
|
@@ -37,10 +39,6 @@ class Chef
|
|
37
39
|
self.run_id = run_status.run_id
|
38
40
|
end
|
39
41
|
|
40
|
-
def run_list_expanded(run_list_expansion)
|
41
|
-
self.recipes = run_list_expansion.recipes
|
42
|
-
end
|
43
|
-
|
44
42
|
def run_completed(_node, _run_status)
|
45
43
|
return unless enabled?
|
46
44
|
|
@@ -47,7 +47,7 @@ class Chef
|
|
47
47
|
registry_key_exists?('HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending')
|
48
48
|
elsif platform?("ubuntu")
|
49
49
|
# This should work for Debian as well if update-notifier-common happens to be installed. We need an API for that.
|
50
|
-
File.
|
50
|
+
File.exist?("/var/run/reboot-required")
|
51
51
|
else
|
52
52
|
false
|
53
53
|
end
|
@@ -33,7 +33,7 @@ class Chef
|
|
33
33
|
module ClassMethods
|
34
34
|
# We want to mix these in as class methods
|
35
35
|
def writable?(path)
|
36
|
-
::File.
|
36
|
+
::File.exist?(path) && Chef::ReservedNames::Win32::File.file_access_check(
|
37
37
|
path, Chef::ReservedNames::Win32::API::Security::FILE_GENERIC_WRITE
|
38
38
|
)
|
39
39
|
end
|
@@ -136,7 +136,7 @@ class Chef
|
|
136
136
|
end
|
137
137
|
|
138
138
|
def should_update_dacl?
|
139
|
-
return true unless ::File.
|
139
|
+
return true unless ::File.exist?(file) || ::File.symlink?(file)
|
140
140
|
|
141
141
|
dacl = target_dacl
|
142
142
|
existing_dacl = existing_descriptor.dacl
|
@@ -170,7 +170,7 @@ class Chef
|
|
170
170
|
end
|
171
171
|
|
172
172
|
def should_update_group?
|
173
|
-
return true unless ::File.
|
173
|
+
return true unless ::File.exist?(file) || ::File.symlink?(file)
|
174
174
|
|
175
175
|
(group = target_group) && (group != existing_descriptor.group)
|
176
176
|
end
|
@@ -190,7 +190,7 @@ class Chef
|
|
190
190
|
end
|
191
191
|
|
192
192
|
def should_update_owner?
|
193
|
-
return true unless ::File.
|
193
|
+
return true unless ::File.exist?(file) || ::File.symlink?(file)
|
194
194
|
|
195
195
|
(owner = target_owner) && (owner != existing_descriptor.owner)
|
196
196
|
end
|
data/lib/chef/file_cache.rb
CHANGED
@@ -79,7 +79,7 @@ class Chef
|
|
79
79
|
|
80
80
|
file_path_array = File.split(path)
|
81
81
|
file_name = file_path_array.pop
|
82
|
-
if File.
|
82
|
+
if File.exist?(file) && File.writable?(file)
|
83
83
|
FileUtils.mv(
|
84
84
|
file,
|
85
85
|
File.join(create_cache_path(File.join(file_path_array), true), file_name)
|
@@ -112,7 +112,7 @@ class Chef
|
|
112
112
|
}
|
113
113
|
)
|
114
114
|
cache_path = create_cache_path(path, false)
|
115
|
-
raise Chef::Exceptions::FileNotFound, "Cannot find #{cache_path} for #{path}!" unless File.
|
115
|
+
raise Chef::Exceptions::FileNotFound, "Cannot find #{cache_path} for #{path}!" unless File.exist?(cache_path)
|
116
116
|
|
117
117
|
if read
|
118
118
|
File.read(cache_path)
|
@@ -139,7 +139,7 @@ class Chef
|
|
139
139
|
}
|
140
140
|
)
|
141
141
|
cache_path = create_cache_path(path, false)
|
142
|
-
if File.
|
142
|
+
if File.exist?(cache_path)
|
143
143
|
File.unlink(cache_path)
|
144
144
|
end
|
145
145
|
true
|
@@ -186,7 +186,7 @@ class Chef
|
|
186
186
|
}
|
187
187
|
)
|
188
188
|
full_path = create_cache_path(path, false)
|
189
|
-
if File.
|
189
|
+
if File.exist?(full_path)
|
190
190
|
true
|
191
191
|
else
|
192
192
|
false
|
data/lib/chef/knife/bootstrap.rb
CHANGED
@@ -217,6 +217,16 @@ class Chef
|
|
217
217
|
description: "Execute the bootstrap via sudo with password.",
|
218
218
|
boolean: false
|
219
219
|
|
220
|
+
# runtime - su user
|
221
|
+
option :su_user,
|
222
|
+
long: "--su-user NAME",
|
223
|
+
description: "The su - USER name to perform bootstrap command using a non-root user."
|
224
|
+
|
225
|
+
# runtime - su user password
|
226
|
+
option :su_password,
|
227
|
+
long: "--su-password PASSWORD",
|
228
|
+
description: "The su USER password for authentication."
|
229
|
+
|
220
230
|
# runtime - client_builder
|
221
231
|
option :chef_node_name,
|
222
232
|
short: "-N NAME",
|
@@ -591,13 +601,31 @@ class Chef
|
|
591
601
|
def perform_bootstrap(remote_bootstrap_script_path)
|
592
602
|
ui.info("Bootstrapping #{ui.color(server_name, :bold)}")
|
593
603
|
cmd = bootstrap_command(remote_bootstrap_script_path)
|
594
|
-
|
604
|
+
bootstrap_run_command(cmd)
|
605
|
+
end
|
606
|
+
|
607
|
+
# Actual bootstrap command to be run on the node.
|
608
|
+
# Handles recursive calls if su USER failed to authenticate.
|
609
|
+
def bootstrap_run_command(cmd)
|
610
|
+
r = connection.run_command(cmd) do |data, channel|
|
595
611
|
ui.msg("#{ui.color(" [#{connection.hostname}]", :cyan)} #{data}")
|
612
|
+
channel.send_data("#{config[:su_password] || config[:connection_password]}\n") if data.match?("Password:")
|
596
613
|
end
|
614
|
+
|
597
615
|
if r.exit_status != 0
|
598
616
|
ui.error("The following error occurred on #{server_name}:")
|
599
|
-
ui.error(r.stderr)
|
600
|
-
exit
|
617
|
+
ui.error("#{r.stdout} #{r.stderr}".strip)
|
618
|
+
exit(r.exit_status)
|
619
|
+
end
|
620
|
+
rescue Train::UserError => e
|
621
|
+
limit ||= 0
|
622
|
+
if e.reason == :bad_su_user_password && limit < 3
|
623
|
+
limit += 1
|
624
|
+
ui.warn("Failed to authenticate su - #{config[:su_user]} to #{server_name}")
|
625
|
+
config[:su_password] = ui.ask("Enter password for su - #{config[:su_user]}@#{server_name}:", echo: false)
|
626
|
+
retry
|
627
|
+
else
|
628
|
+
raise
|
601
629
|
end
|
602
630
|
end
|
603
631
|
|
@@ -1082,7 +1110,17 @@ class Chef
|
|
1082
1110
|
if connection.windows?
|
1083
1111
|
"cmd.exe /C #{remote_path}"
|
1084
1112
|
else
|
1085
|
-
"sh #{remote_path}"
|
1113
|
+
cmd = "sh #{remote_path}"
|
1114
|
+
|
1115
|
+
if config[:su_user]
|
1116
|
+
# su - USER is subject to required an interactive console
|
1117
|
+
# Otherwise, it will raise: su: must be run from a terminal
|
1118
|
+
set_transport_options(pty: true)
|
1119
|
+
cmd = "su - #{config[:su_user]} -c '#{cmd}'"
|
1120
|
+
cmd = "sudo " << cmd if config[:use_sudo]
|
1121
|
+
end
|
1122
|
+
|
1123
|
+
cmd
|
1086
1124
|
end
|
1087
1125
|
end
|
1088
1126
|
|
@@ -1137,6 +1175,18 @@ class Chef
|
|
1137
1175
|
|
1138
1176
|
timeout.to_i
|
1139
1177
|
end
|
1178
|
+
|
1179
|
+
# Train::Transports::SSH::Connection#transport_options
|
1180
|
+
# Append the options to connection transport_options
|
1181
|
+
#
|
1182
|
+
# @param opts [Hash] the opts to be added to connection transport_options.
|
1183
|
+
# @return [Hash] transport_options if the opts contains any option to be set.
|
1184
|
+
#
|
1185
|
+
def set_transport_options(opts)
|
1186
|
+
return unless opts.is_a?(Hash) || !opts.empty?
|
1187
|
+
|
1188
|
+
connection&.connection&.transport_options&.merge! opts
|
1189
|
+
end
|
1140
1190
|
end
|
1141
1191
|
end
|
1142
1192
|
end
|
@@ -446,8 +446,8 @@ class Chef
|
|
446
446
|
# requested new_resource.version constraints
|
447
447
|
logger.trace("#{new_resource} has no existing installed version. Installing install #{candidate_version}")
|
448
448
|
target_version_array.push(candidate_version)
|
449
|
-
elsif version_equals?(current_version, new_version)
|
450
|
-
# this is a short-circuit to avoid needing to
|
449
|
+
elsif !use_magic_version? && version_equals?(current_version, new_version)
|
450
|
+
# this is a short-circuit (mostly for the rubygems provider) to avoid needing to expensively query the candidate_version which must come later
|
451
451
|
logger.trace("#{new_resource} #{package_name} #{new_version} is already installed")
|
452
452
|
target_version_array.push(nil)
|
453
453
|
elsif candidate_version.nil?
|
@@ -64,7 +64,7 @@ def version_tuple(versionstr):
|
|
64
64
|
tmp = versionstr[colon_index + 1:dash_index]
|
65
65
|
if tmp != '':
|
66
66
|
v = tmp
|
67
|
-
arch_index = versionstr.
|
67
|
+
arch_index = versionstr.rfind('.', dash_index)
|
68
68
|
if arch_index > 0:
|
69
69
|
r = versionstr[dash_index + 1:arch_index]
|
70
70
|
else:
|
@@ -42,7 +42,9 @@ class Chef
|
|
42
42
|
end
|
43
43
|
|
44
44
|
def current_installed_version
|
45
|
-
|
45
|
+
# pkgng up to version 1.15.99.7 returns 70 for pkg not found,
|
46
|
+
# later versions return 1
|
47
|
+
pkg_info = shell_out!("pkg", "info", new_resource.package_name, env: nil, returns: [0, 1, 70])
|
46
48
|
pkg_info.stdout[/^Version +: (.+)$/, 1]
|
47
49
|
end
|
48
50
|
|
data/lib/chef/resource.rb
CHANGED
@@ -1062,6 +1062,7 @@ class Chef
|
|
1062
1062
|
# action for the resource.
|
1063
1063
|
#
|
1064
1064
|
# @param name [Symbol] The action name to define.
|
1065
|
+
# @param description [String] optional description for the action
|
1065
1066
|
# @param recipe_block The recipe to run when the action is taken. This block
|
1066
1067
|
# takes no parameters, and will be evaluated in a new context containing:
|
1067
1068
|
#
|
@@ -1071,14 +1072,37 @@ class Chef
|
|
1071
1072
|
#
|
1072
1073
|
# @return The Action class implementing the action
|
1073
1074
|
#
|
1074
|
-
def self.action(action, &recipe_block)
|
1075
|
+
def self.action(action, description: nil, &recipe_block)
|
1075
1076
|
action = action.to_sym
|
1076
1077
|
declare_action_class
|
1077
1078
|
action_class.action(action, &recipe_block)
|
1078
1079
|
self.allowed_actions += [ action ]
|
1080
|
+
# Accept any non-nil description, which will correctly override
|
1081
|
+
# any specific inherited description.
|
1082
|
+
action_descriptions[action] = description unless description.nil?
|
1079
1083
|
default_action action if Array(default_action) == [:nothing]
|
1080
1084
|
end
|
1081
1085
|
|
1086
|
+
# Retrieve the description for a resource's action, if
|
1087
|
+
# any description has been included in the definition.
|
1088
|
+
#
|
1089
|
+
# @param action [Symbol,String] the action name
|
1090
|
+
# @return the description of the action provided, or nil if no description
|
1091
|
+
# was defined
|
1092
|
+
def self.action_description(action)
|
1093
|
+
action_descriptions[action.to_sym]
|
1094
|
+
end
|
1095
|
+
|
1096
|
+
# @api private
|
1097
|
+
#
|
1098
|
+
# @return existing action description hash, or newly-initialized
|
1099
|
+
# hash containing action descriptions inherited from parent Resource,
|
1100
|
+
# if any.
|
1101
|
+
def self.action_descriptions
|
1102
|
+
@action_descriptions ||=
|
1103
|
+
superclass.respond_to?(:action_descriptions) ? superclass.action_descriptions.dup : { nothing: nil }
|
1104
|
+
end
|
1105
|
+
|
1082
1106
|
# Define a method to load up this resource's properties with the current
|
1083
1107
|
# actual values.
|
1084
1108
|
#
|
@@ -1196,9 +1220,9 @@ class Chef
|
|
1196
1220
|
#
|
1197
1221
|
|
1198
1222
|
# FORBIDDEN_IVARS do not show up when the resource is converted to JSON (ie. hidden from data_collector and sending to the chef server via #to_json/to_h/as_json/inspect)
|
1199
|
-
FORBIDDEN_IVARS = %i{@run_context @logger @not_if @only_if @enclosing_provider @description @introduced @examples @validation_message @deprecated @default_description @skip_docs @executed_by_runner}.freeze
|
1223
|
+
FORBIDDEN_IVARS = %i{@run_context @logger @not_if @only_if @enclosing_provider @description @introduced @examples @validation_message @deprecated @default_description @skip_docs @executed_by_runner @action_descriptions}.freeze
|
1200
1224
|
# HIDDEN_IVARS do not show up when the resource is displayed to the user as text (ie. in the error inspector output via #to_text)
|
1201
|
-
HIDDEN_IVARS = %i{@allowed_actions @resource_name @source_line @run_context @logger @name @not_if @only_if @elapsed_time @enclosing_provider @description @introduced @examples @validation_message @deprecated @default_description @skip_docs @executed_by_runner}.freeze
|
1225
|
+
HIDDEN_IVARS = %i{@allowed_actions @resource_name @source_line @run_context @logger @name @not_if @only_if @elapsed_time @enclosing_provider @description @introduced @examples @validation_message @deprecated @default_description @skip_docs @executed_by_runner @action_descriptions}.freeze
|
1202
1226
|
|
1203
1227
|
include Chef::Mixin::ConvertToClassName
|
1204
1228
|
extend Chef::Mixin::ConvertToClassName
|
@@ -76,7 +76,7 @@ class Chef
|
|
76
76
|
default: "MY", equal_to: ["TRUSTEDPUBLISHER", "TrustedPublisher", "CLIENTAUTHISSUER", "REMOTE DESKTOP", "ROOT", "TRUSTEDDEVICES", "WEBHOSTING", "CA", "AUTHROOT", "TRUSTEDPEOPLE", "MY", "SMARTCARDROOT", "TRUST", "DISALLOWED"]
|
77
77
|
|
78
78
|
property :user_store, [TrueClass, FalseClass],
|
79
|
-
description: "Use the
|
79
|
+
description: "Use the `CurrentUser` store instead of the default `LocalMachine` store. Note: Prior to #{ChefUtils::Dist::Infra::CLIENT}. 16.10 this property was ignored.",
|
80
80
|
default: false
|
81
81
|
|
82
82
|
property :cert_path, String,
|
@@ -119,7 +119,7 @@ class Chef
|
|
119
119
|
code_script << acl_script(hash)
|
120
120
|
guard_script << cert_exists_script(hash)
|
121
121
|
|
122
|
-
powershell_script "setting the acls on #{new_resource.source} in #{
|
122
|
+
powershell_script "setting the acls on #{new_resource.source} in #{ps_cert_location}\\#{new_resource.store_name}" do
|
123
123
|
convert_boolean_return true
|
124
124
|
code code_script
|
125
125
|
only_if guard_script
|
@@ -161,25 +161,47 @@ class Chef
|
|
161
161
|
end
|
162
162
|
|
163
163
|
action_class do
|
164
|
+
|
165
|
+
CERT_SYSTEM_STORE_LOCAL_MACHINE = 0x00020000
|
166
|
+
CERT_SYSTEM_STORE_CURRENT_USER = 0x00010000
|
167
|
+
|
164
168
|
def add_cert(cert_obj)
|
165
|
-
store = ::Win32::Certstore.open(new_resource.store_name)
|
169
|
+
store = ::Win32::Certstore.open(new_resource.store_name, store_location: native_cert_location)
|
166
170
|
store.add(cert_obj)
|
167
171
|
end
|
168
172
|
|
169
173
|
def add_pfx_cert
|
170
174
|
exportable = new_resource.exportable ? 1 : 0
|
171
|
-
store = ::Win32::Certstore.open(new_resource.store_name)
|
175
|
+
store = ::Win32::Certstore.open(new_resource.store_name, store_location: native_cert_location)
|
172
176
|
store.add_pfx(new_resource.source, new_resource.pfx_password, exportable)
|
173
177
|
end
|
174
178
|
|
175
179
|
def delete_cert
|
176
|
-
store = ::Win32::Certstore.open(new_resource.store_name)
|
177
|
-
store.delete(new_resource.source)
|
180
|
+
store = ::Win32::Certstore.open(new_resource.store_name, store_location: native_cert_location)
|
181
|
+
store.delete(resolve_thumbprint(new_resource.source))
|
178
182
|
end
|
179
183
|
|
180
184
|
def fetch_cert
|
181
|
-
store = ::Win32::Certstore.open(new_resource.store_name)
|
182
|
-
store.get(new_resource.source)
|
185
|
+
store = ::Win32::Certstore.open(new_resource.store_name, store_location: native_cert_location)
|
186
|
+
store.get(resolve_thumbprint(new_resource.source))
|
187
|
+
end
|
188
|
+
|
189
|
+
# Thumbprints should be exactly 40 Hex characters
|
190
|
+
def valid_thumbprint?(string)
|
191
|
+
string.scan(/\H/).empty? && string.length == 40
|
192
|
+
end
|
193
|
+
|
194
|
+
def get_thumbprint(store_name, location, source)
|
195
|
+
<<-GETTHUMBPRINTCODE
|
196
|
+
$content = Get-ChildItem -Path Cert:\\#{location}\\#{store_name} | Where-Object {$_.Subject -Match "#{source}"} | Select-Object Thumbprint
|
197
|
+
$content.thumbprint
|
198
|
+
GETTHUMBPRINTCODE
|
199
|
+
end
|
200
|
+
|
201
|
+
def resolve_thumbprint(thumbprint)
|
202
|
+
return thumbprint if valid_thumbprint?(thumbprint)
|
203
|
+
|
204
|
+
powershell_exec!(get_thumbprint(new_resource.store_name, ps_cert_location, new_resource.source)).result
|
183
205
|
end
|
184
206
|
|
185
207
|
# Checks whether a certificate with the given thumbprint
|
@@ -187,9 +209,11 @@ class Chef
|
|
187
209
|
# If the certificate is not present, verify_cert returns a String: "Certificate not found"
|
188
210
|
# But if it is present but expired, it returns a Boolean: false
|
189
211
|
# Otherwise, it returns a Boolean: true
|
212
|
+
# updated this method to accept either a subject name or a thumbprint - 1/29/2021
|
213
|
+
|
190
214
|
def verify_cert(thumbprint = new_resource.source)
|
191
|
-
store = ::Win32::Certstore.open(new_resource.store_name)
|
192
|
-
store.valid?(thumbprint)
|
215
|
+
store = ::Win32::Certstore.open(new_resource.store_name, store_location: native_cert_location)
|
216
|
+
store.valid?(resolve_thumbprint(thumbprint))
|
193
217
|
end
|
194
218
|
|
195
219
|
def show_or_store_cert(cert_obj)
|
@@ -230,13 +254,19 @@ class Chef
|
|
230
254
|
out_file.close
|
231
255
|
end
|
232
256
|
|
233
|
-
|
234
|
-
|
257
|
+
# this array structure is solving 2 problems. The first is that we need to have support for both the CurrentUser AND LocalMachine stores
|
258
|
+
# Secondly, we need to pass the proper constant name for each store to win32-certstore but also pass the short name to powershell scripts used here
|
259
|
+
def ps_cert_location
|
260
|
+
new_resource.user_store ? "CurrentUser" : "LocalMachine"
|
261
|
+
end
|
262
|
+
|
263
|
+
def native_cert_location
|
264
|
+
new_resource.user_store ? CERT_SYSTEM_STORE_CURRENT_USER : CERT_SYSTEM_STORE_LOCAL_MACHINE
|
235
265
|
end
|
236
266
|
|
237
267
|
def cert_script(persist)
|
238
268
|
cert_script = "$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2"
|
239
|
-
file = Chef::Util::PathHelper.cleanpath(new_resource.source)
|
269
|
+
file = Chef::Util::PathHelper.cleanpath(new_resource.source, ps_cert_location)
|
240
270
|
cert_script << " \"#{file}\""
|
241
271
|
if ::File.extname(file.downcase) == ".pfx"
|
242
272
|
cert_script << ", \"#{new_resource.pfx_password}\""
|
@@ -252,14 +282,14 @@ class Chef
|
|
252
282
|
def cert_exists_script(hash)
|
253
283
|
<<-EOH
|
254
284
|
$hash = #{hash}
|
255
|
-
Test-Path "Cert:\\#{
|
285
|
+
Test-Path "Cert:\\#{ps_cert_location}\\#{new_resource.store_name}\\$hash"
|
256
286
|
EOH
|
257
287
|
end
|
258
288
|
|
259
289
|
def within_store_script
|
260
290
|
inner_script = yield "$store"
|
261
291
|
<<-EOH
|
262
|
-
$store = New-Object System.Security.Cryptography.X509Certificates.X509Store "#{new_resource.store_name}", ([System.Security.Cryptography.X509Certificates.StoreLocation]::#{
|
292
|
+
$store = New-Object System.Security.Cryptography.X509Certificates.X509Store "#{new_resource.store_name}", ([System.Security.Cryptography.X509Certificates.StoreLocation]::#{ps_cert_location})
|
263
293
|
$store.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::ReadWrite)
|
264
294
|
#{inner_script}
|
265
295
|
$store.Close()
|
@@ -273,7 +303,7 @@ class Chef
|
|
273
303
|
# and from https://msdn.microsoft.com/en-us/library/windows/desktop/bb204778(v=vs.85).aspx
|
274
304
|
set_acl_script = <<-EOH
|
275
305
|
$hash = #{hash}
|
276
|
-
$storeCert = Get-ChildItem "cert:\\#{
|
306
|
+
$storeCert = Get-ChildItem "cert:\\#{ps_cert_location}\\#{new_resource.store_name}\\$hash"
|
277
307
|
if ($storeCert -eq $null) { throw 'no key exists.' }
|
278
308
|
$keyname = $storeCert.PrivateKey.CspKeyContainerInfo.UniqueKeyContainerName
|
279
309
|
if ($keyname -eq $null) { throw 'no private key exists.' }
|
@@ -340,7 +370,7 @@ class Chef
|
|
340
370
|
if verify_cert(thumbprint) == true
|
341
371
|
Chef::Log.debug("Certificate is already present")
|
342
372
|
else
|
343
|
-
converge_by("Adding certificate #{new_resource.source} into Store #{new_resource.store_name}") do
|
373
|
+
converge_by("Adding certificate #{new_resource.source} into #{ps_cert_location} Store #{new_resource.store_name}") do
|
344
374
|
if is_pfx
|
345
375
|
add_pfx_cert
|
346
376
|
else
|
@@ -41,7 +41,11 @@ class Chef
|
|
41
41
|
data[:description] = resource.description
|
42
42
|
# data[:deprecated] = resource.deprecated || false
|
43
43
|
data[:default_action] = resource.default_action
|
44
|
-
data[:actions] =
|
44
|
+
data[:actions] = {}
|
45
|
+
resource.allowed_actions.each do |action|
|
46
|
+
data[:actions][action] = resource.action_description(action)
|
47
|
+
end
|
48
|
+
|
45
49
|
data[:examples] = resource.examples
|
46
50
|
data[:introduced] = resource.introduced
|
47
51
|
data[:preview] = resource.preview_resource
|
data/lib/chef/shell.rb
CHANGED
@@ -25,6 +25,7 @@ require "pp" unless defined?(PP)
|
|
25
25
|
require "etc" unless defined?(Etc)
|
26
26
|
require "mixlib/cli" unless defined?(Mixlib::CLI)
|
27
27
|
require "chef-utils/dist" unless defined?(ChefUtils::Dist)
|
28
|
+
require "chef-config/mixin/dot_d"
|
28
29
|
|
29
30
|
require_relative "../chef"
|
30
31
|
require_relative "version"
|
@@ -211,6 +212,7 @@ module Shell
|
|
211
212
|
|
212
213
|
class Options
|
213
214
|
include Mixlib::CLI
|
215
|
+
include ChefConfig::Mixin::DotD
|
214
216
|
|
215
217
|
def self.footer(text = nil)
|
216
218
|
@footer = text if text
|
@@ -341,15 +343,44 @@ module Shell
|
|
341
343
|
# We have to nuke ARGV to make sure irb's option parser never sees it.
|
342
344
|
# otherwise, IRB complains about command line switches it doesn't recognize.
|
343
345
|
ARGV.clear
|
346
|
+
|
347
|
+
# This code should not exist.
|
348
|
+
# We should be using Application::Client and then calling load_config_file
|
349
|
+
# which does all this properly. However this will do for now.
|
344
350
|
config[:config_file] = config_file_for_shell_mode(environment)
|
345
351
|
config_msg = config[:config_file] || "none (standalone session)"
|
346
352
|
puts "loading configuration: #{config_msg}"
|
347
|
-
|
353
|
+
|
354
|
+
# load the config (if we have one)
|
355
|
+
unless config[:config_file].nil?
|
356
|
+
if File.exist?(config[:config_file]) && File.readable?(config[:config_file])
|
357
|
+
Chef::Config.from_file(config[:config_file])
|
358
|
+
end
|
359
|
+
|
360
|
+
# even if we couldn't load that, we need to tell Chef::Config what
|
361
|
+
# the file was so it sets conf dir and d_dir and such properly
|
362
|
+
Chef::Config[:config_file] = config[:config_file]
|
363
|
+
|
364
|
+
# now attempt to load any relevant dot-dirs
|
365
|
+
load_dot_d(Chef::Config[:client_d_dir]) if Chef::Config[:client_d_dir]
|
366
|
+
end
|
367
|
+
|
368
|
+
# finally merge command-line options in
|
348
369
|
Chef::Config.merge!(config)
|
349
370
|
end
|
350
371
|
|
351
372
|
private
|
352
373
|
|
374
|
+
# shamelessly lifted from application.rb
|
375
|
+
def apply_config(config_content, config_file_path)
|
376
|
+
Chef::Config.from_string(config_content, config_file_path)
|
377
|
+
rescue Exception => error
|
378
|
+
logger.fatal("Configuration error #{error.class}: #{error.message}")
|
379
|
+
filtered_trace = error.backtrace.grep(/#{Regexp.escape(config_file_path)}/)
|
380
|
+
filtered_trace.each { |line| logger.fatal(" " + line ) }
|
381
|
+
raise Chef::Exceptions::ConfigurationError.new("Aborting due to error in '#{config_file_path}': #{error}")
|
382
|
+
end
|
383
|
+
|
353
384
|
def config_file_for_shell_mode(environment)
|
354
385
|
dot_chef_dir = Chef::Util::PathHelper.home(".chef")
|
355
386
|
if config[:config_file]
|
@@ -105,7 +105,7 @@ class Chef::Util::DSC
|
|
105
105
|
# The name may not be null or empty, and should start with a letter.
|
106
106
|
def validate_configuration_name!(configuration_name)
|
107
107
|
if !!(configuration_name =~ /\A[A-Za-z]+[_a-zA-Z0-9]*\Z/) == false
|
108
|
-
raise ArgumentError,
|
108
|
+
raise ArgumentError, "Configuration `#{configuration_name}` is not a valid PowerShell cmdlet name"
|
109
109
|
end
|
110
110
|
end
|
111
111
|
|
data/lib/chef/version.rb
CHANGED
data/lib/chef/version_string.rb
CHANGED
@@ -13,7 +13,7 @@
|
|
13
13
|
# See the License for the specific language governing permissions and
|
14
14
|
# limitations under the License.
|
15
15
|
|
16
|
-
require "chef-utils/version_string"
|
16
|
+
require "chef-utils/version_string" unless defined?(ChefUtils::VersionString)
|
17
17
|
|
18
18
|
class Chef
|
19
19
|
VersionString = ChefUtils::VersionString
|
@@ -19,10 +19,6 @@
|
|
19
19
|
require "spec_helper"
|
20
20
|
|
21
21
|
describe Chef::Resource::Ohai do
|
22
|
-
let(:ohai) do
|
23
|
-
OHAI_SYSTEM
|
24
|
-
end
|
25
|
-
|
26
22
|
let(:node) { Chef::Node.new }
|
27
23
|
|
28
24
|
let(:run_context) do
|
@@ -34,13 +30,9 @@ describe Chef::Resource::Ohai do
|
|
34
30
|
|
35
31
|
shared_examples_for "reloaded :uptime" do
|
36
32
|
it "should reload :uptime" do
|
37
|
-
|
38
|
-
|
39
|
-
# Sleep for a second so the uptime gets updated.
|
40
|
-
sleep 1
|
41
|
-
|
33
|
+
expect(node[:uptime_seconds]).to be nil
|
42
34
|
ohai_resource.run_action(:reload)
|
43
|
-
expect(node[:
|
35
|
+
expect(Integer(node[:uptime_seconds])).to be_an(Integer)
|
44
36
|
end
|
45
37
|
end
|
46
38
|
|
@@ -223,6 +223,10 @@ module ResourceActionSpec
|
|
223
223
|
ActionJackson.succeeded = ActionJackson.ruby_block_converged
|
224
224
|
end
|
225
225
|
|
226
|
+
action :test1, description: "Original description" do
|
227
|
+
true
|
228
|
+
end
|
229
|
+
|
226
230
|
def foo_public
|
227
231
|
"foo_public!"
|
228
232
|
end
|
@@ -293,7 +297,12 @@ module ResourceActionSpec
|
|
293
297
|
ActionJackalope.jackalope_ran = :access_attribute
|
294
298
|
ActionJackalope.succeeded = ActionJackson.succeeded
|
295
299
|
end
|
300
|
+
|
301
|
+
action :test1, description: "An old action with a new description" do
|
302
|
+
super
|
303
|
+
end
|
296
304
|
end
|
305
|
+
|
297
306
|
before do
|
298
307
|
ActionJackalope.jackalope_ran = nil
|
299
308
|
ActionJackalope.load_current_resource_ran = nil
|
@@ -344,6 +353,11 @@ module ResourceActionSpec
|
|
344
353
|
expect(ActionJackalope.succeeded).to eq "foo!alope blarghle! bar!alope"
|
345
354
|
end
|
346
355
|
|
356
|
+
it "allows overridden action to have a description separate from the action defined in the base resource" do
|
357
|
+
expect(ActionJackson.action_description(:test1)).to eql "Original description"
|
358
|
+
expect(ActionJackalope.action_description(:test1)).to eql "An old action with a new description"
|
359
|
+
end
|
360
|
+
|
347
361
|
it "non-overridden actions run and can access overridden and non-overridden variables (but not necessarily new ones)" do
|
348
362
|
converge do
|
349
363
|
action_jackalope "hi" do
|
data/spec/spec_helper.rb
CHANGED
@@ -87,7 +87,7 @@ Dir["spec/support/**/*.rb"]
|
|
87
87
|
.each { |f| require f }
|
88
88
|
|
89
89
|
OHAI_SYSTEM = Ohai::System.new
|
90
|
-
OHAI_SYSTEM.all_plugins(["platform", "hostname", "languages/powershell"])
|
90
|
+
OHAI_SYSTEM.all_plugins(["platform", "hostname", "languages/powershell", "uptime"])
|
91
91
|
|
92
92
|
test_node = Chef::Node.new
|
93
93
|
test_node.automatic["os"] = (OHAI_SYSTEM["os"] || "unknown_os").dup.freeze
|
@@ -8,41 +8,39 @@ describe Chef::Compliance::Runner do
|
|
8
8
|
described_class.new.tap do |r|
|
9
9
|
r.node = node
|
10
10
|
r.run_id = "my_run_id"
|
11
|
-
r.recipes = []
|
12
11
|
end
|
13
12
|
end
|
14
13
|
|
15
14
|
describe "#enabled?" do
|
15
|
+
|
16
16
|
it "is true if the node attributes have audit profiles and the audit cookbook is not present" do
|
17
17
|
node.normal["audit"]["profiles"]["ssh"] = { 'compliance': "base/ssh" }
|
18
|
-
runner.recipes = %w{ fancy_cookbook::fanciness tacobell::nachos }
|
19
18
|
|
20
19
|
expect(runner).to be_enabled
|
21
20
|
end
|
22
21
|
|
23
22
|
it "is false if the node attributes have audit profiles and the audit cookbook is present" do
|
23
|
+
stub_const("::Reporter::ChefAutomate", true)
|
24
24
|
node.normal["audit"]["profiles"]["ssh"] = { 'compliance': "base/ssh" }
|
25
|
-
runner.recipes = %w{ audit::default fancy_cookbook::fanciness tacobell::nachos }
|
26
25
|
|
27
26
|
expect(runner).not_to be_enabled
|
28
27
|
end
|
29
28
|
|
30
29
|
it "is false if the node attributes do not have audit profiles and the audit cookbook is not present" do
|
31
30
|
node.normal["audit"]["profiles"] = {}
|
32
|
-
runner.recipes = %w{ fancy_cookbook::fanciness tacobell::nachos }
|
33
31
|
|
34
32
|
expect(runner).not_to be_enabled
|
35
33
|
end
|
36
34
|
|
37
35
|
it "is false if the node attributes do not have audit profiles and the audit cookbook is present" do
|
38
|
-
|
39
|
-
|
36
|
+
stub_const("::Reporter::ChefAutomate", true)
|
37
|
+
node.automatic["recipes"] = %w{ audit::default fancy_cookbook::fanciness tacobell::nachos }
|
40
38
|
|
41
39
|
expect(runner).not_to be_enabled
|
42
40
|
end
|
43
41
|
|
44
42
|
it "is false if the node attributes do not have audit attributes and the audit cookbook is not present" do
|
45
|
-
|
43
|
+
node.automatic["recipes"] = %w{ fancy_cookbook::fanciness tacobell::nachos }
|
46
44
|
expect(runner).not_to be_enabled
|
47
45
|
end
|
48
46
|
end
|
@@ -57,12 +57,12 @@ describe Chef::DSL::RebootPending do
|
|
57
57
|
end
|
58
58
|
|
59
59
|
it "should return true if /var/run/reboot-required exists" do
|
60
|
-
allow(File).to receive(:
|
60
|
+
allow(File).to receive(:exist?).with("/var/run/reboot-required").and_return(true)
|
61
61
|
expect(recipe.reboot_pending?).to be_truthy
|
62
62
|
end
|
63
63
|
|
64
64
|
it "should return false if /var/run/reboot-required does not exist" do
|
65
|
-
allow(File).to receive(:
|
65
|
+
allow(File).to receive(:exist?).with("/var/run/reboot-required").and_return(false)
|
66
66
|
expect(recipe.reboot_pending?).to be_falsey
|
67
67
|
end
|
68
68
|
end
|
@@ -115,7 +115,7 @@ describe Chef::Formatters::ErrorInspectors::ResourceFailureInspector do
|
|
115
115
|
# fake code to run through #recipe_snippet
|
116
116
|
source_file = [ "if true", "var = non_existent", "end" ]
|
117
117
|
allow(IO).to receive(:readlines).and_return(source_file)
|
118
|
-
allow(File).to receive(:
|
118
|
+
allow(File).to receive(:exist?).and_return(true)
|
119
119
|
end
|
120
120
|
|
121
121
|
it "parses a Windows path" do
|
@@ -141,7 +141,7 @@ describe Chef::Formatters::ErrorInspectors::ResourceFailureInspector do
|
|
141
141
|
|
142
142
|
context "when the recipe file does not exist" do
|
143
143
|
before do
|
144
|
-
allow(File).to receive(:
|
144
|
+
allow(File).to receive(:exist?).and_return(false)
|
145
145
|
allow(IO).to receive(:readlines).and_raise(Errno::ENOENT)
|
146
146
|
end
|
147
147
|
|
@@ -1726,7 +1726,8 @@ describe Chef::Knife::Bootstrap do
|
|
1726
1726
|
|
1727
1727
|
describe "#perform_bootstrap" do
|
1728
1728
|
let(:exit_status) { 0 }
|
1729
|
-
let(:
|
1729
|
+
let(:stdout) { "" }
|
1730
|
+
let(:result_mock) { double("result", exit_status: exit_status, stderr: "A message", stdout: stdout) }
|
1730
1731
|
|
1731
1732
|
before do
|
1732
1733
|
allow(connection).to receive(:hostname).and_return "testhost"
|
@@ -1739,12 +1740,13 @@ describe Chef::Knife::Bootstrap do
|
|
1739
1740
|
expect(connection)
|
1740
1741
|
.to receive(:run_command)
|
1741
1742
|
.with("sh /path.sh")
|
1742
|
-
.and_yield("output here")
|
1743
|
+
.and_yield("output here", nil)
|
1743
1744
|
.and_return result_mock
|
1744
1745
|
|
1745
1746
|
expect(knife.ui).to receive(:msg).with(/testhost/)
|
1746
1747
|
knife.perform_bootstrap("/path.sh")
|
1747
1748
|
end
|
1749
|
+
|
1748
1750
|
context "when the remote command fails" do
|
1749
1751
|
let(:exit_status) { 1 }
|
1750
1752
|
it "shows an error and exits" do
|
@@ -1756,6 +1758,25 @@ describe Chef::Knife::Bootstrap do
|
|
1756
1758
|
expect { knife.perform_bootstrap("/path.sh") }.to raise_error(SystemExit)
|
1757
1759
|
end
|
1758
1760
|
end
|
1761
|
+
|
1762
|
+
context "when the remote command failed due to su auth error" do
|
1763
|
+
let(:exit_status) { 1 }
|
1764
|
+
let(:stdout) { "su: Authentication failure" }
|
1765
|
+
let(:connection_obj) { double("connection", transport_options: {}) }
|
1766
|
+
it "shows an error and exits" do
|
1767
|
+
allow(connection).to receive(:connection).and_return(connection_obj)
|
1768
|
+
expect(knife.ui).to receive(:info).with(/Bootstrapping.*/)
|
1769
|
+
expect(knife).to receive(:bootstrap_command)
|
1770
|
+
.with("/path.sh")
|
1771
|
+
.and_return("su - USER -c 'sh /path.sh'")
|
1772
|
+
expect(connection)
|
1773
|
+
.to receive(:run_command)
|
1774
|
+
.with("su - USER -c 'sh /path.sh'")
|
1775
|
+
.and_yield("output here", nil)
|
1776
|
+
.and_raise(Train::UserError)
|
1777
|
+
expect { knife.perform_bootstrap("/path.sh") }.to raise_error(Train::UserError)
|
1778
|
+
end
|
1779
|
+
end
|
1759
1780
|
end
|
1760
1781
|
|
1761
1782
|
describe "#connect!" do
|
@@ -1964,7 +1985,25 @@ describe Chef::Knife::Bootstrap do
|
|
1964
1985
|
context "under Linux" do
|
1965
1986
|
let(:linux_test) { true }
|
1966
1987
|
it "prefixes the command to run under sh" do
|
1967
|
-
expect(knife.bootstrap_command("bootstrap")).to eq "sh bootstrap"
|
1988
|
+
expect(knife.bootstrap_command("bootstrap.sh")).to eq "sh bootstrap.sh"
|
1989
|
+
end
|
1990
|
+
|
1991
|
+
context "with --su-user option" do
|
1992
|
+
let(:connection_obj) { double("connection", transport_options: {}) }
|
1993
|
+
before do
|
1994
|
+
knife.config[:su_user] = "root"
|
1995
|
+
allow(connection).to receive(:connection).and_return(connection_obj)
|
1996
|
+
end
|
1997
|
+
it "prefixes the command to run using su -USER -c" do
|
1998
|
+
expect(knife.bootstrap_command("bootstrap.sh")).to eq "su - #{knife.config[:su_user]} -c 'sh bootstrap.sh'"
|
1999
|
+
expect(connection_obj.transport_options.key?(:pty)).to eq true
|
2000
|
+
end
|
2001
|
+
|
2002
|
+
it "sudo appended if --sudo option enabled" do
|
2003
|
+
knife.config[:use_sudo] = true
|
2004
|
+
expect(knife.bootstrap_command("bootstrap.sh")).to eq "sudo su - #{knife.config[:su_user]} -c 'sh bootstrap.sh'"
|
2005
|
+
expect(connection_obj.transport_options.key?(:pty)).to eq true
|
2006
|
+
end
|
1968
2007
|
end
|
1969
2008
|
end
|
1970
2009
|
end
|
@@ -46,7 +46,9 @@ describe Chef::Knife::SupermarketShare do
|
|
46
46
|
|
47
47
|
allow(@knife).to receive(:shell_out!).and_return(true)
|
48
48
|
@stdout = StringIO.new
|
49
|
+
@stderr = StringIO.new
|
49
50
|
allow(@knife.ui).to receive(:stdout).and_return(@stdout)
|
51
|
+
allow(@knife.ui).to receive(:stderr).and_return(@stderr)
|
50
52
|
end
|
51
53
|
|
52
54
|
describe "run" do
|
@@ -140,7 +142,9 @@ describe Chef::Knife::SupermarketShare do
|
|
140
142
|
before do
|
141
143
|
allow(Chef::CookbookSiteStreamingUploader).to receive(:create_build_dir).and_return("/var/tmp/dummy")
|
142
144
|
@knife.config = { dry_run: true }
|
143
|
-
|
145
|
+
@so = instance_double("Mixlib::ShellOut")
|
146
|
+
allow(@knife).to receive(:shell_out!).and_return(@so)
|
147
|
+
allow(@so).to receive(:stdout).and_return("file")
|
144
148
|
end
|
145
149
|
|
146
150
|
it "should list files in the tarball" do
|
@@ -151,7 +155,6 @@ describe Chef::Knife::SupermarketShare do
|
|
151
155
|
end
|
152
156
|
|
153
157
|
it "does not upload the cookbook" do
|
154
|
-
allow(@knife).to receive(:shell_out!).and_return(true)
|
155
158
|
expect(@knife).not_to receive(:do_upload)
|
156
159
|
@knife.run
|
157
160
|
end
|
@@ -164,10 +167,6 @@ describe Chef::Knife::SupermarketShare do
|
|
164
167
|
@upload_response = double("Net::HTTPResponse")
|
165
168
|
allow(Chef::CookbookSiteStreamingUploader).to receive(:post).and_return(@upload_response)
|
166
169
|
|
167
|
-
@stdout = StringIO.new
|
168
|
-
@stderr = StringIO.new
|
169
|
-
allow(@knife.ui).to receive(:stdout).and_return(@stdout)
|
170
|
-
allow(@knife.ui).to receive(:stderr).and_return(@stderr)
|
171
170
|
allow(File).to receive(:open).and_return(true)
|
172
171
|
end
|
173
172
|
|
@@ -19,11 +19,17 @@ require "spec_helper"
|
|
19
19
|
|
20
20
|
# NOTE: most of the tests of this functionality are baked into the func tests for the dnf package provider
|
21
21
|
|
22
|
-
|
22
|
+
# run this test only for following platforms.
|
23
|
+
exclude_test = !(%w{rhel fedora amazon}.include?(ohai[:platform_family]) && File.exist?("/usr/bin/dnf"))
|
24
|
+
describe Chef::Provider::Package::Dnf::PythonHelper, :requires_root, external: exclude_test do
|
23
25
|
let(:helper) { Chef::Provider::Package::Dnf::PythonHelper.instance }
|
24
26
|
|
25
27
|
it "propagates stacktraces on stderr from the forked subprocess", :rhel do
|
26
28
|
allow(helper).to receive(:dnf_command).and_return("ruby -e 'raise \"your hands in the air\"'")
|
27
29
|
expect { helper.package_query(:whatprovides, "tcpdump") }.to raise_error(/your hands in the air/)
|
28
30
|
end
|
31
|
+
|
32
|
+
it "compares EVRAs with dots in the release correctly" do
|
33
|
+
expect(helper.compare_versions("0:1.8.29-6.el8.x86_64", "0:1.8.29-6.el8_3.1.x86_64")).to eql(-1)
|
34
|
+
end
|
29
35
|
end
|
@@ -66,7 +66,7 @@ describe Chef::Provider::Package::Freebsd::Port do
|
|
66
66
|
end
|
67
67
|
|
68
68
|
it "should query pkg database" do
|
69
|
-
expect(@provider).to receive(:shell_out_compacted!).with("pkg", "info", "zsh", env: nil, returns: [0, 70], timeout: 900).and_return(@pkg_info)
|
69
|
+
expect(@provider).to receive(:shell_out_compacted!).with("pkg", "info", "zsh", env: nil, returns: [0, 1, 70], timeout: 900).and_return(@pkg_info)
|
70
70
|
expect(@provider.current_installed_version).to eq("3.1.7")
|
71
71
|
end
|
72
72
|
end
|
@@ -28,7 +28,11 @@ class DummyResource < Chef::Resource
|
|
28
28
|
introduced "14.0"
|
29
29
|
property :first, String, description: "My First Property", introduced: "14.0"
|
30
30
|
|
31
|
-
action :dummy do
|
31
|
+
action :dummy, description: "Dummy action" do
|
32
|
+
return true
|
33
|
+
end
|
34
|
+
|
35
|
+
action :dummy_no_desc do
|
32
36
|
return true
|
33
37
|
end
|
34
38
|
end
|
@@ -39,7 +43,8 @@ describe Chef::ResourceInspector do
|
|
39
43
|
|
40
44
|
it "returns a hash with required data" do
|
41
45
|
expect(subject[:description]).to eq "A dummy resource"
|
42
|
-
expect(subject[:actions]).to
|
46
|
+
expect(subject[:actions]).to eq({ nothing: nil, dummy: "Dummy action",
|
47
|
+
dummy_no_desc: nil })
|
43
48
|
end
|
44
49
|
|
45
50
|
context "excluding built in properties" do
|
data/spec/unit/resource_spec.rb
CHANGED
@@ -1162,6 +1162,52 @@ describe Chef::Resource do
|
|
1162
1162
|
end
|
1163
1163
|
end
|
1164
1164
|
|
1165
|
+
describe "#action_description" do
|
1166
|
+
class TestResource < ::Chef::Resource
|
1167
|
+
action :symbol_action, description: "a symbol test" do; end
|
1168
|
+
action "string_action", description: "a string test" do; end
|
1169
|
+
action :base_action0 do; end
|
1170
|
+
action :base_action1, description: "unmodified base action 1 desc" do; end
|
1171
|
+
action :base_action2, description: "unmodified base action 2 desc" do; end
|
1172
|
+
action :base_action3, description: "unmodified base action 3 desc" do; end
|
1173
|
+
end
|
1174
|
+
|
1175
|
+
it "returns nil when no description was provided for the action" do
|
1176
|
+
expect(TestResource.action_description(:base_action0)).to eql(nil)
|
1177
|
+
end
|
1178
|
+
|
1179
|
+
context "when action definition is a string" do
|
1180
|
+
it "returns the description whether a symbol or string is used to look it up" do
|
1181
|
+
expect(TestResource.action_description("string_action")).to eql("a string test")
|
1182
|
+
expect(TestResource.action_description(:string_action)).to eql("a string test")
|
1183
|
+
end
|
1184
|
+
end
|
1185
|
+
|
1186
|
+
context "when action definition is a symbol" do
|
1187
|
+
it "returns the description whether a symbol or string is used to look up" do
|
1188
|
+
expect(TestResource.action_description("symbol_action")).to eql("a symbol test")
|
1189
|
+
expect(TestResource.action_description(:symbol_action)).to eql("a symbol test")
|
1190
|
+
end
|
1191
|
+
end
|
1192
|
+
|
1193
|
+
context "when inheriting from an existing resource" do
|
1194
|
+
class TestResourceChild < TestResource
|
1195
|
+
action :base_action2, description: "modified base action 2 desc" do; end
|
1196
|
+
action :base_action3 do; end
|
1197
|
+
end
|
1198
|
+
|
1199
|
+
it "returns original description when a described action is not overridden in child resource" do
|
1200
|
+
expect(TestResourceChild.action_description(:base_action1)).to eq "unmodified base action 1 desc"
|
1201
|
+
end
|
1202
|
+
it "returns original description when the child resource overrides an inherited action but NOT its description" do
|
1203
|
+
expect(TestResourceChild.action_description(:base_action3)).to eq "unmodified base action 3 desc"
|
1204
|
+
end
|
1205
|
+
it "returns new description when the child resource overrides an inherited action and its description" do
|
1206
|
+
expect(TestResourceChild.action_description(:base_action2)).to eq "modified base action 2 desc"
|
1207
|
+
end
|
1208
|
+
end
|
1209
|
+
end
|
1210
|
+
|
1165
1211
|
describe ".default_action" do
|
1166
1212
|
let(:default_action) {}
|
1167
1213
|
let(:resource_class) do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: chef
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 16.
|
4
|
+
version: 16.10.8
|
5
5
|
platform: universal-mingw32
|
6
6
|
authors:
|
7
7
|
- Adam Jacob
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-02-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: chef-config
|
@@ -16,28 +16,28 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - '='
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 16.
|
19
|
+
version: 16.10.8
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - '='
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 16.
|
26
|
+
version: 16.10.8
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: chef-utils
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - '='
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 16.
|
33
|
+
version: 16.10.8
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - '='
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 16.
|
40
|
+
version: 16.10.8
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: train-core
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -554,16 +554,22 @@ dependencies:
|
|
554
554
|
name: uuidtools
|
555
555
|
requirement: !ruby/object:Gem::Requirement
|
556
556
|
requirements:
|
557
|
-
- - "
|
557
|
+
- - ">="
|
558
558
|
- !ruby/object:Gem::Version
|
559
559
|
version: 2.1.5
|
560
|
+
- - "<"
|
561
|
+
- !ruby/object:Gem::Version
|
562
|
+
version: '3.0'
|
560
563
|
type: :runtime
|
561
564
|
prerelease: false
|
562
565
|
version_requirements: !ruby/object:Gem::Requirement
|
563
566
|
requirements:
|
564
|
-
- - "
|
567
|
+
- - ">="
|
565
568
|
- !ruby/object:Gem::Version
|
566
569
|
version: 2.1.5
|
570
|
+
- - "<"
|
571
|
+
- !ruby/object:Gem::Version
|
572
|
+
version: '3.0'
|
567
573
|
- !ruby/object:Gem::Dependency
|
568
574
|
name: proxifier
|
569
575
|
requirement: !ruby/object:Gem::Requirement
|
@@ -750,14 +756,14 @@ dependencies:
|
|
750
756
|
requirements:
|
751
757
|
- - "~>"
|
752
758
|
- !ruby/object:Gem::Version
|
753
|
-
version: '0.
|
759
|
+
version: '0.5'
|
754
760
|
type: :runtime
|
755
761
|
prerelease: false
|
756
762
|
version_requirements: !ruby/object:Gem::Requirement
|
757
763
|
requirements:
|
758
764
|
- - "~>"
|
759
765
|
- !ruby/object:Gem::Version
|
760
|
-
version: '0.
|
766
|
+
version: '0.5'
|
761
767
|
description: A systems integration framework, built to bring the benefits of configuration
|
762
768
|
management to your entire infrastructure.
|
763
769
|
email: adam@chef.io
|