chef 16.9.32-universal-mingw32 → 16.10.8-universal-mingw32
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 +1 -1
- data/chef-universal-mingw32.gemspec +1 -1
- data/lib/chef/compliance/runner.rb +2 -2
- 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/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 +2 -2
- data/lib/chef/util/dsc/configuration_generator.rb +1 -1
- data/lib/chef/version.rb +1 -1
- data/spec/integration/recipes/resource_action_spec.rb +14 -0
- 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/resource_inspector_spec.rb +7 -2
- data/spec/unit/resource_spec.rb +46 -0
- metadata +8 -8
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
@@ -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
|
|
@@ -20,8 +20,8 @@ class Chef
|
|
20
20
|
# renamed from Chef Visibility in 2017, so should capture all modern versions of the audit cookbook.
|
21
21
|
audit_cookbook_present = defined?(::Reporter::ChefAutomate)
|
22
22
|
|
23
|
-
logger.
|
24
|
-
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}")
|
25
25
|
|
26
26
|
inspec_profiles.any? && !audit_cookbook_present
|
27
27
|
end
|
@@ -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:
|
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
@@ -352,13 +352,13 @@ module Shell
|
|
352
352
|
puts "loading configuration: #{config_msg}"
|
353
353
|
|
354
354
|
# load the config (if we have one)
|
355
|
-
|
355
|
+
unless config[:config_file].nil?
|
356
356
|
if File.exist?(config[:config_file]) && File.readable?(config[:config_file])
|
357
357
|
Chef::Config.from_file(config[:config_file])
|
358
358
|
end
|
359
359
|
|
360
360
|
# even if we couldn't load that, we need to tell Chef::Config what
|
361
|
-
# the file was so it sets
|
361
|
+
# the file was so it sets conf dir and d_dir and such properly
|
362
362
|
Chef::Config[:config_file] = config[:config_file]
|
363
363
|
|
364
364
|
# now attempt to load any relevant dot-dirs
|
@@ -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
@@ -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
|
@@ -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
|
@@ -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
|
@@ -756,14 +756,14 @@ dependencies:
|
|
756
756
|
requirements:
|
757
757
|
- - "~>"
|
758
758
|
- !ruby/object:Gem::Version
|
759
|
-
version: '0.
|
759
|
+
version: '0.5'
|
760
760
|
type: :runtime
|
761
761
|
prerelease: false
|
762
762
|
version_requirements: !ruby/object:Gem::Requirement
|
763
763
|
requirements:
|
764
764
|
- - "~>"
|
765
765
|
- !ruby/object:Gem::Version
|
766
|
-
version: '0.
|
766
|
+
version: '0.5'
|
767
767
|
description: A systems integration framework, built to bring the benefits of configuration
|
768
768
|
management to your entire infrastructure.
|
769
769
|
email: adam@chef.io
|