chef 15.6.10-universal-mingw32 → 15.7.30-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 +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"
|