chef 15.6.10-universal-mingw32 → 15.7.30-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/README.md +2 -2
- data/lib/chef/chef_fs/file_system/chef_server/cookbooks_dir.rb +22 -5
- data/lib/chef/cookbook/cookbook_version_loader.rb +12 -6
- data/lib/chef/cookbook_loader.rb +55 -2
- data/lib/chef/cookbook_uploader.rb +2 -0
- data/lib/chef/cookbook_version.rb +17 -0
- data/lib/chef/dist.rb +3 -3
- data/lib/chef/event_loggers/windows_eventlog.rb +1 -1
- data/lib/chef/knife/bootstrap.rb +5 -0
- data/lib/chef/knife/bootstrap/templates/chef-full.erb +11 -11
- data/lib/chef/knife/cookbook_upload.rb +75 -45
- data/lib/chef/knife/core/bootstrap_context.rb +5 -5
- data/lib/chef/knife/core/windows_bootstrap_context.rb +1 -1
- data/lib/chef/knife/supermarket_install.rb +1 -1
- data/lib/chef/log/winevt.rb +1 -1
- data/lib/chef/mixin/openssl_helper.rb +21 -0
- data/lib/chef/monkey_patches/net_http.rb +0 -38
- data/lib/chef/provider/cron.rb +54 -9
- data/lib/chef/provider/cron/aix.rb +9 -2
- data/lib/chef/provider/launchd.rb +1 -1
- data/lib/chef/provider/user/aix.rb +1 -1
- data/lib/chef/provider/user/mac.rb +17 -22
- data/lib/chef/provider/windows_task.rb +2 -2
- data/lib/chef/resource/archive_file.rb +5 -2
- data/lib/chef/resource/cron.rb +29 -0
- data/lib/chef/resource/cron_d.rb +29 -0
- data/lib/chef/resource/openssl_x509_certificate.rb +32 -21
- data/lib/chef/resource/sudo.rb +13 -4
- data/lib/chef/version.rb +2 -2
- data/lib/chef/version_string.rb +3 -126
- data/spec/data/cookbooks/apache2/metadata.json +33 -0
- data/spec/data/cookbooks/java/metadata.json +33 -0
- data/spec/functional/event_loggers/windows_eventlog_spec.rb +5 -5
- data/spec/integration/knife/chef_fs_data_store_spec.rb +7 -2
- data/spec/integration/knife/cookbook_upload_spec.rb +10 -0
- data/spec/integration/knife/deps_spec.rb +11 -0
- data/spec/integration/knife/upload_spec.rb +115 -14
- data/spec/unit/cookbook/cookbook_version_loader_spec.rb +7 -4
- data/spec/unit/knife/cookbook_upload_spec.rb +79 -18
- data/spec/unit/mixin/openssl_helper_spec.rb +42 -0
- data/spec/unit/provider/cron_spec.rb +127 -0
- data/spec/unit/provider/user/aix_spec.rb +2 -2
- metadata +8 -6
@@ -158,11 +158,11 @@ class Chef
|
|
158
158
|
end
|
159
159
|
|
160
160
|
if encrypted_data_bag_secret
|
161
|
-
client_rb << %Q{encrypted_data_bag_secret "
|
161
|
+
client_rb << %Q{encrypted_data_bag_secret "/etc/chef/encrypted_data_bag_secret"\n}
|
162
162
|
end
|
163
163
|
|
164
164
|
unless trusted_certs.empty?
|
165
|
-
client_rb << %Q{trusted_certs_dir "
|
165
|
+
client_rb << %Q{trusted_certs_dir "/etc/chef/trusted_certs"\n}
|
166
166
|
end
|
167
167
|
|
168
168
|
if Chef::Config[:fips]
|
@@ -175,7 +175,7 @@ class Chef
|
|
175
175
|
def start_chef
|
176
176
|
# If the user doesn't have a client path configure, let bash use the PATH for what it was designed for
|
177
177
|
client_path = @chef_config[:chef_client_path] || "#{Chef::Dist::CLIENT}"
|
178
|
-
s = "#{client_path} -j
|
178
|
+
s = "#{client_path} -j /etc/chef/first-boot.json"
|
179
179
|
if @config[:verbosity] && @config[:verbosity] >= 3
|
180
180
|
s << " -l trace"
|
181
181
|
elsif @config[:verbosity] && @config[:verbosity] >= 2
|
@@ -226,7 +226,7 @@ class Chef
|
|
226
226
|
content = ""
|
227
227
|
if @chef_config[:trusted_certs_dir]
|
228
228
|
Dir.glob(File.join(Chef::Util::PathHelper.escape_glob_dir(@chef_config[:trusted_certs_dir]), "*.{crt,pem}")).each do |cert|
|
229
|
-
content << "cat >
|
229
|
+
content << "cat > /etc/chef/trusted_certs/#{File.basename(cert)} <<'EOP'\n" +
|
230
230
|
IO.read(File.expand_path(cert)) + "\nEOP\n"
|
231
231
|
end
|
232
232
|
end
|
@@ -240,7 +240,7 @@ class Chef
|
|
240
240
|
root.find do |f|
|
241
241
|
relative = f.relative_path_from(root)
|
242
242
|
if f != root
|
243
|
-
file_on_node = "
|
243
|
+
file_on_node = "/etc/chef/client.d/#{relative}"
|
244
244
|
if f.directory?
|
245
245
|
content << "mkdir #{file_on_node}\n"
|
246
246
|
else
|
@@ -158,7 +158,7 @@ class Chef
|
|
158
158
|
|
159
159
|
def start_chef
|
160
160
|
bootstrap_environment_option = bootstrap_environment.nil? ? "" : " -E #{bootstrap_environment}"
|
161
|
-
start_chef = "SET \"PATH=%SystemRoot%\\system32;%SystemRoot%;%SystemRoot%\\System32\\Wbem;%SYSTEMROOT%\\System32\\WindowsPowerShell\\v1.0\\;C:\\ruby\\bin;C:\\opscode\\chef\\bin;C:\\opscode\\chef\\embedded\\bin
|
161
|
+
start_chef = "SET \"PATH=%SystemRoot%\\system32;%SystemRoot%;%SystemRoot%\\System32\\Wbem;%SYSTEMROOT%\\System32\\WindowsPowerShell\\v1.0\\;C:\\ruby\\bin;C:\\opscode\\chef\\bin;C:\\opscode\\chef\\embedded\\bin\;%PATH%\"\n"
|
162
162
|
start_chef << "chef-client -c c:/chef/client.rb -j c:/chef/first-boot.json#{bootstrap_environment_option}\n"
|
163
163
|
end
|
164
164
|
|
@@ -137,7 +137,7 @@ class Chef
|
|
137
137
|
end
|
138
138
|
|
139
139
|
def download_cookbook_to(download_path)
|
140
|
-
downloader = Chef::Knife::
|
140
|
+
downloader = Chef::Knife::SupermarketDownload.new
|
141
141
|
downloader.config[:file] = download_path
|
142
142
|
downloader.config[:supermarket_site] = config[:supermarket_site]
|
143
143
|
downloader.name_args = name_args
|
data/lib/chef/log/winevt.rb
CHANGED
@@ -401,6 +401,27 @@ class Chef
|
|
401
401
|
crl.sign(ca_private_key, ::OpenSSL::Digest::SHA256.new)
|
402
402
|
crl
|
403
403
|
end
|
404
|
+
|
405
|
+
# Return true if a certificate need to be renewed (or doesn't exist) according to the number
|
406
|
+
# of days before expiration given
|
407
|
+
# @param [string] cert_file path of the cert file or cert content
|
408
|
+
# @param [integer] renew_before_expiry number of days before expiration
|
409
|
+
# @return [true, false]
|
410
|
+
def cert_need_renewall?(cert_file, renew_before_expiry)
|
411
|
+
resp = true
|
412
|
+
cert_content = ::File.exist?(cert_file) ? File.read(cert_file) : cert_file
|
413
|
+
begin
|
414
|
+
cert = OpenSSL::X509::Certificate.new cert_content
|
415
|
+
rescue ::OpenSSL::X509::CertificateError
|
416
|
+
return resp
|
417
|
+
end
|
418
|
+
|
419
|
+
unless cert.not_after <= Time.now + 3600 * 24 * renew_before_expiry
|
420
|
+
resp = false
|
421
|
+
end
|
422
|
+
|
423
|
+
resp
|
424
|
+
end
|
404
425
|
end
|
405
426
|
end
|
406
427
|
end
|
@@ -24,41 +24,3 @@ module Net
|
|
24
24
|
include ChefNetHTTPExceptionExtensions
|
25
25
|
end
|
26
26
|
end
|
27
|
-
|
28
|
-
if Net::HTTP.instance_methods.map(&:to_s).include?("proxy_uri")
|
29
|
-
begin
|
30
|
-
# Ruby 2.0 changes the way proxy support is implemented in Net::HTTP.
|
31
|
-
# The implementation does not work correctly with IPv6 literals because it
|
32
|
-
# concatenates the address into a URI without adding square brackets for
|
33
|
-
# IPv6 addresses.
|
34
|
-
#
|
35
|
-
# If the bug is present, a call to Net::HTTP#proxy_uri when the host is an
|
36
|
-
# IPv6 address will fail by creating an invalid URI, like so:
|
37
|
-
#
|
38
|
-
# ruby -r'net/http' -e 'Net::HTTP.new("::1", 80).proxy_uri'
|
39
|
-
# /Users/ddeleo/.rbenv/versions/2.0.0-p247/lib/ruby/2.0.0/uri/generic.rb:214:in `initialize': the scheme http does not accept registry part: ::1:80 (or bad hostname?) (URI::InvalidURIError)
|
40
|
-
# from /Users/ddeleo/.rbenv/versions/2.0.0-p247/lib/ruby/2.0.0/uri/http.rb:84:in `initialize'
|
41
|
-
# from /Users/ddeleo/.rbenv/versions/2.0.0-p247/lib/ruby/2.0.0/uri/common.rb:214:in `new'
|
42
|
-
# from /Users/ddeleo/.rbenv/versions/2.0.0-p247/lib/ruby/2.0.0/uri/common.rb:214:in `parse'
|
43
|
-
# from /Users/ddeleo/.rbenv/versions/2.0.0-p247/lib/ruby/2.0.0/uri/common.rb:747:in `parse'
|
44
|
-
# from /Users/ddeleo/.rbenv/versions/2.0.0-p247/lib/ruby/2.0.0/uri/common.rb:994:in `URI'
|
45
|
-
# from /Users/ddeleo/.rbenv/versions/2.0.0-p247/lib/ruby/2.0.0/net/http.rb:1027:in `proxy_uri'
|
46
|
-
# from -e:1:in `<main>'
|
47
|
-
#
|
48
|
-
# https://bugs.ruby-lang.org/issues/9129
|
49
|
-
#
|
50
|
-
# NOTE: This should be fixed in Ruby 2.2.0, and backported to Ruby 2.0 and
|
51
|
-
# 2.1 (not yet released so the version/patchlevel required isn't known
|
52
|
-
# yet).
|
53
|
-
Net::HTTP.new("::1", 80).proxy_uri
|
54
|
-
rescue URI::InvalidURIError
|
55
|
-
class Net::HTTP
|
56
|
-
|
57
|
-
def proxy_uri # :nodoc:
|
58
|
-
ipv6_safe_addr = address.to_s.include?(":") ? "[#{address}]" : address
|
59
|
-
@proxy_uri ||= URI("http://#{ipv6_safe_addr}:#{port}").find_proxy
|
60
|
-
end
|
61
|
-
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
data/lib/chef/provider/cron.rb
CHANGED
@@ -216,11 +216,13 @@ class Chef
|
|
216
216
|
raise Chef::Exceptions::Cron, "Error updating state of #{new_resource.name}, error: #{e}"
|
217
217
|
end
|
218
218
|
|
219
|
-
|
220
|
-
|
221
|
-
|
219
|
+
#
|
220
|
+
# @return [String] The string of Env Variables containing line breaks.
|
221
|
+
#
|
222
|
+
def env_var_str
|
223
|
+
str = []
|
222
224
|
%i{mailto path shell home}.each do |v|
|
223
|
-
|
225
|
+
str << "#{v.to_s.upcase}=\"#{new_resource.send(v)}\"" if new_resource.send(v)
|
224
226
|
end
|
225
227
|
new_resource.environment.each do |name, value|
|
226
228
|
if ENVIRONMENT_PROPERTIES.include?(name)
|
@@ -228,20 +230,63 @@ class Chef
|
|
228
230
|
logger.warn("#{new_resource.name}: the environment property contains the '#{name}' variable, which should be set separately as a property.")
|
229
231
|
new_resource.send(name.downcase.to_sym, value.gsub(/^"|"$/, ""))
|
230
232
|
new_resource.environment.delete(name)
|
231
|
-
|
233
|
+
str << "#{name.to_s.upcase}=\"#{value}\""
|
232
234
|
else
|
233
235
|
raise Chef::Exceptions::Cron, "#{new_resource.name}: the '#{name}' property is set and environment property also contains the '#{name}' variable. Remove the variable from the environment property."
|
234
236
|
end
|
235
237
|
else
|
236
|
-
|
238
|
+
str << "#{name}=#{value}"
|
237
239
|
end
|
238
240
|
end
|
241
|
+
str.join("\n")
|
242
|
+
end
|
243
|
+
|
244
|
+
#
|
245
|
+
# @return [String] The Cron time string consisting five fields that Cron converts into a time interval.
|
246
|
+
#
|
247
|
+
def duration_str
|
239
248
|
if new_resource.time
|
240
|
-
|
249
|
+
"@#{new_resource.time}"
|
241
250
|
else
|
242
|
-
|
251
|
+
"#{new_resource.minute} #{new_resource.hour} #{new_resource.day} #{new_resource.month} #{new_resource.weekday}"
|
243
252
|
end
|
244
|
-
|
253
|
+
end
|
254
|
+
|
255
|
+
#
|
256
|
+
# @return [String] The timeout command string formed as per time_out property.
|
257
|
+
#
|
258
|
+
def time_out_str
|
259
|
+
return "" if new_resource.time_out.empty?
|
260
|
+
|
261
|
+
str = " timeout"
|
262
|
+
str << " --preserve-status" if new_resource.time_out["preserve-status"].to_s.downcase == "true"
|
263
|
+
str << " --foreground" if new_resource.time_out["foreground"].to_s.downcase == "true"
|
264
|
+
str << " --kill-after #{new_resource.time_out["kill-after"]}" if new_resource.time_out["kill-after"]
|
265
|
+
str << " --signal #{new_resource.time_out["signal"]}" if new_resource.time_out["signal"]
|
266
|
+
str << " #{new_resource.time_out["duration"]};"
|
267
|
+
str
|
268
|
+
end
|
269
|
+
|
270
|
+
#
|
271
|
+
# @return [String] The command to be executed. The new line at the end has been added purposefully.
|
272
|
+
#
|
273
|
+
def cmd_str
|
274
|
+
" #{new_resource.command}\n"
|
275
|
+
end
|
276
|
+
|
277
|
+
# Concatenates various information and formulates a complete string that
|
278
|
+
# could be written in the crontab
|
279
|
+
#
|
280
|
+
# @return [String] A crontab string formed as per the user inputs.
|
281
|
+
#
|
282
|
+
def get_crontab_entry
|
283
|
+
# Initialize
|
284
|
+
newcron = []
|
285
|
+
newcron << "# Chef Name: #{new_resource.name}"
|
286
|
+
newcron << env_var_str unless env_var_str.empty?
|
287
|
+
newcron << duration_str + time_out_str + cmd_str
|
288
|
+
|
289
|
+
newcron.join("\n")
|
245
290
|
end
|
246
291
|
|
247
292
|
def weekday_in_crontab
|
@@ -33,8 +33,11 @@ class Chef
|
|
33
33
|
raise Chef::Exceptions::Cron, "Aix cron entry does not support environment variables. Please set them in script and use script in cron."
|
34
34
|
end
|
35
35
|
|
36
|
-
|
37
|
-
|
36
|
+
if time_out_set?
|
37
|
+
raise Chef::Exceptions::Cron, "Aix cron entry does not support timeout."
|
38
|
+
end
|
39
|
+
|
40
|
+
newcron = "# Chef Name: #{new_resource.name}\n"
|
38
41
|
newcron << "#{@new_resource.minute} #{@new_resource.hour} #{@new_resource.day} #{@new_resource.month} #{@new_resource.weekday}"
|
39
42
|
|
40
43
|
newcron << " #{@new_resource.command}\n"
|
@@ -44,6 +47,10 @@ class Chef
|
|
44
47
|
def env_vars_are_set?
|
45
48
|
@new_resource.environment.length > 0 || !@new_resource.mailto.nil? || !@new_resource.path.nil? || !@new_resource.shell.nil? || !@new_resource.home.nil?
|
46
49
|
end
|
50
|
+
|
51
|
+
def time_out_set?
|
52
|
+
!@new_resource.time_out.empty?
|
53
|
+
end
|
47
54
|
end
|
48
55
|
end
|
49
56
|
end
|
@@ -194,7 +194,7 @@ class Chef
|
|
194
194
|
"environment_variables" => "EnvironmentVariables",
|
195
195
|
"exit_timeout" => "ExitTimeout",
|
196
196
|
"ld_group" => "GroupName",
|
197
|
-
"hard_resource_limits" => "
|
197
|
+
"hard_resource_limits" => "HardResourceLimits",
|
198
198
|
"inetd_compatibility" => "inetdCompatibility",
|
199
199
|
"init_groups" => "InitGroups",
|
200
200
|
"keep_alive" => "KeepAlive",
|
@@ -110,7 +110,7 @@ class Chef
|
|
110
110
|
return unless current_resource.password != new_resource.password && new_resource.password
|
111
111
|
|
112
112
|
logger.trace("#{new_resource.username} setting password to #{new_resource.password}")
|
113
|
-
command = "echo '#{new_resource.username}:#{new_resource.password}' | chpasswd -e"
|
113
|
+
command = "echo '#{new_resource.username}:#{new_resource.password}' | chpasswd -c -e"
|
114
114
|
shell_out!(command)
|
115
115
|
end
|
116
116
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
#
|
2
2
|
# Author:: Ryan Cragun (<ryan@chef.io>)
|
3
|
-
# Copyright:: Copyright (c) 2019, Chef Software Inc.
|
3
|
+
# Copyright:: Copyright (c) 2019-2019, Chef Software Inc.
|
4
4
|
# License:: Apache License, Version 2.0
|
5
5
|
#
|
6
6
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
@@ -92,6 +92,8 @@ class Chef
|
|
92
92
|
|
93
93
|
@user_plist = Plist.new(::Plist.parse_xml(user_xml))
|
94
94
|
|
95
|
+
return unless user_plist[:shadow_hash]
|
96
|
+
|
95
97
|
shadow_hash_hex = user_plist[:shadow_hash][0]
|
96
98
|
return unless shadow_hash_hex && shadow_hash_hex != ""
|
97
99
|
|
@@ -148,14 +150,12 @@ class Chef
|
|
148
150
|
cmd += ["-adminPassword", new_resource.admin_password]
|
149
151
|
end
|
150
152
|
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
raise Chef::Exceptions::User, "error when creating user: #{res}"
|
158
|
-
end
|
153
|
+
# sysadminctl doesn't exit with a non-zero exit code if it encounters
|
154
|
+
# a problem. We'll check stderr and make sure we see that it finished
|
155
|
+
# correctly.
|
156
|
+
res = run_sysadminctl(cmd)
|
157
|
+
unless res.downcase =~ /creating user/
|
158
|
+
raise Chef::Exceptions::User, "error when creating user: #{res}"
|
159
159
|
end
|
160
160
|
|
161
161
|
# Wait for the user to show up in the ds cache
|
@@ -289,11 +289,9 @@ class Chef
|
|
289
289
|
|
290
290
|
# sysadminctl doesn't exit with a non-zero exit code if it encounters
|
291
291
|
# a problem. We'll check stderr and make sure we see that it finished
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
raise Chef::Exceptions::User, "error deleting user: #{res}"
|
296
|
-
end
|
292
|
+
res = run_sysadminctl(cmd)
|
293
|
+
unless res.downcase =~ /deleting record|not found/
|
294
|
+
raise Chef::Exceptions::User, "error deleting user: #{res}"
|
297
295
|
end
|
298
296
|
|
299
297
|
reload_user_plist
|
@@ -301,18 +299,15 @@ class Chef
|
|
301
299
|
end
|
302
300
|
|
303
301
|
def lock_user
|
304
|
-
|
305
|
-
run_dscl("append", "/Users/#{new_resource.username}", "AuthenticationAuthority", ";DisabledUser;")
|
306
|
-
end
|
302
|
+
run_dscl("append", "/Users/#{new_resource.username}", "AuthenticationAuthority", ";DisabledUser;")
|
307
303
|
|
308
304
|
reload_user_plist
|
309
305
|
end
|
310
306
|
|
311
307
|
def unlock_user
|
312
308
|
auth_string = user_plist[:auth_authority].reject! { |tag| tag == ";DisabledUser;" }.join.strip
|
313
|
-
|
314
|
-
|
315
|
-
end
|
309
|
+
|
310
|
+
run_dscl("create", "/Users/#{new_resource.username}", "AuthenticationAuthority", auth_string)
|
316
311
|
|
317
312
|
reload_user_plist
|
318
313
|
end
|
@@ -483,7 +478,7 @@ class Chef
|
|
483
478
|
)
|
484
479
|
end
|
485
480
|
|
486
|
-
shadow_hash = user_plist[:shadow_hash][0]
|
481
|
+
shadow_hash = user_plist[:shadow_hash] ? user_plist[:shadow_hash][0] : {}
|
487
482
|
shadow_hash["SALTED-SHA512-PBKDF2"] = {
|
488
483
|
"entropy" => entropy,
|
489
484
|
"salt" => salt,
|
@@ -533,7 +528,7 @@ class Chef
|
|
533
528
|
run_dsimport(import_file, "/Local/Default", "M")
|
534
529
|
run_dscl("create", "/Users/#{new_resource.username}", "Password", "********")
|
535
530
|
ensure
|
536
|
-
::File.delete(import_file) if
|
531
|
+
::File.delete(import_file) if import_file && ::File.exist?(import_file)
|
537
532
|
end
|
538
533
|
|
539
534
|
def wait_for_user
|
@@ -328,7 +328,7 @@ class Chef
|
|
328
328
|
def task_needs_update?(task)
|
329
329
|
flag = false
|
330
330
|
if new_resource.frequency == :none
|
331
|
-
flag = (task.
|
331
|
+
flag = (task.author != new_resource.user ||
|
332
332
|
task.application_name != new_resource.command ||
|
333
333
|
description_needs_update?(task) ||
|
334
334
|
task.parameters != new_resource.command_arguments.to_s ||
|
@@ -352,7 +352,7 @@ class Chef
|
|
352
352
|
current_task_trigger[:type] != new_task_trigger[:type] ||
|
353
353
|
current_task_trigger[:random_minutes_interval].to_i != new_task_trigger[:random_minutes_interval].to_i ||
|
354
354
|
current_task_trigger[:minutes_interval].to_i != new_task_trigger[:minutes_interval].to_i ||
|
355
|
-
task.
|
355
|
+
task.author.to_s.casecmp(new_resource.user.to_s) != 0 ||
|
356
356
|
task.application_name != new_resource.command ||
|
357
357
|
description_needs_update?(task) ||
|
358
358
|
task.parameters != new_resource.command_arguments.to_s ||
|
@@ -102,8 +102,11 @@ class Chef
|
|
102
102
|
end
|
103
103
|
|
104
104
|
if new_resource.owner || new_resource.group
|
105
|
-
converge_by("set owner of #{new_resource.destination} to #{new_resource.owner}:#{new_resource.group}") do
|
106
|
-
|
105
|
+
converge_by("set owner of files extracted in #{new_resource.destination} to #{new_resource.owner}:#{new_resource.group}") do
|
106
|
+
archive = Archive::Reader.open_filename(new_resource.path)
|
107
|
+
archive.each_entry do |e|
|
108
|
+
FileUtils.chown(new_resource.owner, new_resource.group, "#{new_resource.destination}/#{e.pathname}")
|
109
|
+
end
|
107
110
|
end
|
108
111
|
end
|
109
112
|
end
|
data/lib/chef/resource/cron.rb
CHANGED
@@ -162,6 +162,35 @@ class Chef
|
|
162
162
|
description: "A Hash of environment variables in the form of ({'ENV_VARIABLE' => 'VALUE'}).",
|
163
163
|
default: lazy { {} }
|
164
164
|
|
165
|
+
TIMEOUT_OPTS = %w{duration preserve-status foreground kill-after signal}.freeze
|
166
|
+
TIMEOUT_REGEX = /\A\S+/.freeze
|
167
|
+
|
168
|
+
property :time_out, Hash,
|
169
|
+
description: "A Hash of timeouts in the form of ({'OPTION' => 'VALUE'}).
|
170
|
+
Accepted valid options are:
|
171
|
+
preserve-status (BOOL, default: 'false'),
|
172
|
+
foreground (BOOL, default: 'false'),
|
173
|
+
kill-after (in seconds),
|
174
|
+
signal (a name like 'HUP' or a number)",
|
175
|
+
default: lazy { {} },
|
176
|
+
introduced: "15.7",
|
177
|
+
coerce: proc { |h|
|
178
|
+
if h.is_a?(Hash)
|
179
|
+
invalid_keys = h.keys - TIMEOUT_OPTS
|
180
|
+
unless invalid_keys.empty?
|
181
|
+
error_msg = "Key of option time_out must be equal to one of: \"#{TIMEOUT_OPTS.join('", "')}\"! You passed \"#{invalid_keys.join(", ")}\"."
|
182
|
+
raise Chef::Exceptions::ValidationFailed, error_msg
|
183
|
+
end
|
184
|
+
unless h.values.all? { |x| x =~ TIMEOUT_REGEX }
|
185
|
+
error_msg = "Values of option time_out should be non-empty string without any leading whitespaces."
|
186
|
+
raise Chef::Exceptions::ValidationFailed, error_msg
|
187
|
+
end
|
188
|
+
h
|
189
|
+
elsif h.is_a?(Integer) || h.is_a?(String)
|
190
|
+
{ "duration" => h }
|
191
|
+
end
|
192
|
+
}
|
193
|
+
|
165
194
|
private
|
166
195
|
|
167
196
|
def integerize(integerish)
|
data/lib/chef/resource/cron_d.rb
CHANGED
@@ -206,6 +206,35 @@ class Chef
|
|
206
206
|
description: "A Hash containing additional arbitrary environment variables under which the cron job will be run in the form of ``({'ENV_VARIABLE' => 'VALUE'})``.",
|
207
207
|
default: lazy { {} }
|
208
208
|
|
209
|
+
TIMEOUT_OPTS = %w{duration preserve-status foreground kill-after signal}.freeze
|
210
|
+
TIMEOUT_REGEX = /\A\S+/.freeze
|
211
|
+
|
212
|
+
property :time_out, Hash,
|
213
|
+
description: "A Hash of timeouts in the form of ({'OPTION' => 'VALUE'}).
|
214
|
+
Accepted valid options are:
|
215
|
+
preserve-status (BOOL, default: 'false'),
|
216
|
+
foreground (BOOL, default: 'false'),
|
217
|
+
kill-after (in seconds),
|
218
|
+
signal (a name like 'HUP' or a number)",
|
219
|
+
default: lazy { {} },
|
220
|
+
introduced: "15.7",
|
221
|
+
coerce: proc { |h|
|
222
|
+
if h.is_a?(Hash)
|
223
|
+
invalid_keys = h.keys - TIMEOUT_OPTS
|
224
|
+
unless invalid_keys.empty?
|
225
|
+
error_msg = "Key of option time_out must be equal to one of: \"#{TIMEOUT_OPTS.join('", "')}\"! You passed \"#{invalid_keys.join(", ")}\"."
|
226
|
+
raise Chef::Exceptions::ValidationFailed, error_msg
|
227
|
+
end
|
228
|
+
unless h.values.all? { |x| x =~ TIMEOUT_REGEX }
|
229
|
+
error_msg = "Values of option time_out should be non-empty string without any leading whitespaces."
|
230
|
+
raise Chef::Exceptions::ValidationFailed, error_msg
|
231
|
+
end
|
232
|
+
h
|
233
|
+
elsif h.is_a?(Integer) || h.is_a?(String)
|
234
|
+
{ "duration" => h }
|
235
|
+
end
|
236
|
+
}
|
237
|
+
|
209
238
|
property :mode, [String, Integer],
|
210
239
|
description: "The octal mode of the generated crontab file.",
|
211
240
|
default: "0600"
|