chef 14.5.33-universal-mingw32 → 14.6.47-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 +5 -3
- data/chef-universal-mingw32.gemspec +3 -2
- data/chef.gemspec +3 -4
- data/lib/chef/api_client.rb +5 -3
- data/lib/chef/api_client_v1.rb +6 -4
- data/lib/chef/application.rb +1 -1
- data/lib/chef/audit/audit_reporter.rb +1 -1
- data/lib/chef/audit/control_group_data.rb +12 -6
- data/lib/chef/chef_fs/chef_fs_data_store.rb +2 -2
- data/lib/chef/chef_fs/data_handler/data_handler_base.rb +1 -1
- data/lib/chef/cookbook/manifest_v0.rb +34 -29
- data/lib/chef/cookbook/manifest_v2.rb +15 -11
- data/lib/chef/cookbook/metadata.rb +4 -2
- data/lib/chef/cookbook_manifest.rb +8 -5
- data/lib/chef/cookbook_version.rb +1 -1
- data/lib/chef/data_bag.rb +4 -2
- data/lib/chef/data_bag_item.rb +5 -3
- data/lib/chef/data_collector.rb +2 -2
- data/lib/chef/data_collector/resource_report.rb +4 -4
- data/lib/chef/encrypted_data_bag_item.rb +4 -2
- data/lib/chef/environment.rb +4 -2
- data/lib/chef/file_content_management/deploy/mv_unix.rb +5 -4
- data/lib/chef/handler.rb +2 -2
- data/lib/chef/json_compat.rb +1 -1
- data/lib/chef/key.rb +7 -5
- data/lib/chef/knife/bootstrap.rb +7 -1
- data/lib/chef/knife/client_edit.rb +2 -2
- data/lib/chef/knife/data_bag_show.rb +2 -2
- data/lib/chef/knife/osc_user_edit.rb +2 -2
- data/lib/chef/knife/user_edit.rb +2 -2
- data/lib/chef/mixin/params_validate.rb +4 -2
- data/lib/chef/node/attribute.rb +4 -4
- data/lib/chef/org.rb +6 -4
- data/lib/chef/policy_builder/policyfile.rb +5 -3
- data/lib/chef/provider/package.rb +9 -4
- data/lib/chef/provider/package/windows.rb +23 -1
- data/lib/chef/provider/package/yum/yum_helper.py +3 -2
- data/lib/chef/provider/package/zypper.rb +12 -8
- data/lib/chef/provider/registry_key.rb +15 -6
- data/lib/chef/provider/user/windows.rb +4 -3
- data/lib/chef/provider/windows_task.rb +11 -2
- data/lib/chef/resource.rb +3 -1
- data/lib/chef/resource/locale.rb +1 -1
- data/lib/chef/resource/ohai_hint.rb +4 -4
- data/lib/chef/resource/rhsm_errata_level.rb +1 -1
- data/lib/chef/resource/timezone.rb +91 -0
- data/lib/chef/resource/user/windows_user.rb +4 -0
- data/lib/chef/resource/windows_task.rb +240 -238
- data/lib/chef/resource/zypper_package.rb +5 -0
- data/lib/chef/resource_collection/resource_collection_serialization.rb +4 -2
- data/lib/chef/resources.rb +1 -0
- data/lib/chef/role.rb +4 -2
- data/lib/chef/run_list/run_list_expansion.rb +5 -3
- data/lib/chef/run_status.rb +4 -2
- data/lib/chef/user.rb +7 -5
- data/lib/chef/user_v1.rb +8 -6
- data/lib/chef/version.rb +1 -1
- data/lib/chef/win32/security/sid.rb +39 -0
- data/spec/functional/assets/zypprepo/chef_rpm-1.10-1.aarch64.rpm +0 -0
- data/spec/functional/assets/zypprepo/chef_rpm-1.10-1.i686.rpm +0 -0
- data/spec/functional/assets/zypprepo/chef_rpm-1.10-1.ppc64.rpm +0 -0
- data/spec/functional/assets/zypprepo/chef_rpm-1.10-1.ppc64le.rpm +0 -0
- data/spec/functional/assets/zypprepo/chef_rpm-1.10-1.s390x.rpm +0 -0
- data/spec/functional/assets/zypprepo/chef_rpm-1.10-1.src.rpm +0 -0
- data/spec/functional/assets/zypprepo/chef_rpm-1.10-1.x86_64.rpm +0 -0
- data/spec/functional/assets/zypprepo/chef_rpm-1.2-1.aarch64.rpm +0 -0
- data/spec/functional/assets/zypprepo/chef_rpm-1.2-1.i686.rpm +0 -0
- data/spec/functional/assets/zypprepo/chef_rpm-1.2-1.ppc64.rpm +0 -0
- data/spec/functional/assets/zypprepo/chef_rpm-1.2-1.ppc64le.rpm +0 -0
- data/spec/functional/assets/zypprepo/chef_rpm-1.2-1.s390x.rpm +0 -0
- data/spec/functional/assets/zypprepo/chef_rpm-1.2-1.src.rpm +0 -0
- data/spec/functional/assets/zypprepo/chef_rpm-1.2-1.x86_64.rpm +0 -0
- data/spec/functional/http/simple_spec.rb +2 -2
- data/spec/functional/resource/remote_file_spec.rb +2 -2
- data/spec/functional/resource/user/windows_spec.rb +1 -1
- data/spec/functional/resource/windows_task_spec.rb +1 -1
- data/spec/functional/resource/zypper_package_spec.rb +233 -0
- data/spec/spec_helper.rb +1 -0
- data/spec/unit/audit/audit_reporter_spec.rb +4 -4
- data/spec/unit/audit/control_group_data_spec.rb +17 -17
- data/spec/unit/environment_spec.rb +1 -1
- data/spec/unit/file_content_management/deploy/mv_unix_spec.rb +13 -1
- data/spec/unit/node_spec.rb +33 -0
- data/spec/unit/provider/package/rpm_spec.rb +5 -5
- data/spec/unit/provider/package/zypper_spec.rb +51 -0
- data/spec/unit/provider/package_spec.rb +32 -2
- data/spec/unit/provider/registry_key_spec.rb +74 -0
- data/spec/unit/provider/user/windows_spec.rb +12 -3
- data/spec/unit/provider/windows_task_spec.rb +1 -0
- data/spec/unit/resource/timezone.rb +39 -0
- data/spec/unit/resource/windows_task_spec.rb +1 -1
- data/spec/unit/resource_collection_spec.rb +1 -1
- data/spec/unit/run_context/child_run_context_spec.rb +3 -3
- data/spec/unit/shell/shell_session_spec.rb +3 -2
- metadata +37 -41
- data/CONTRIBUTING.md +0 -152
- data/VERSION +0 -1
@@ -361,9 +361,14 @@ class Chef
|
|
361
361
|
#
|
362
362
|
# By default, this function will use Gem::Version comparison. Subclasses can reimplement this method
|
363
363
|
# for package-management system specific versions.
|
364
|
+
#
|
365
|
+
# (In other words, pull requests to introduce domain specific mangling of versions into this method
|
366
|
+
# will be closed -- that logic must go into the subclass -- we understand that this is far from perfect
|
367
|
+
# but it is a better default than outright buggy things like v1.to_f <=> v2.to_f)
|
368
|
+
#
|
364
369
|
def version_compare(v1, v2)
|
365
|
-
gem_v1 = Gem::Version.new(v1)
|
366
|
-
gem_v2 = Gem::Version.new(v2)
|
370
|
+
gem_v1 = Gem::Version.new(v1.gsub(/\A\s*(#{Gem::Version::VERSION_PATTERN}).*/, '\1'))
|
371
|
+
gem_v2 = Gem::Version.new(v2.gsub(/\A\s*(#{Gem::Version::VERSION_PATTERN}).*/, '\1'))
|
367
372
|
|
368
373
|
gem_v1 <=> gem_v2
|
369
374
|
end
|
@@ -491,7 +496,7 @@ class Chef
|
|
491
496
|
elsif current_version.nil?
|
492
497
|
logger.trace("#{new_resource} has no existing installed version. Installing install #{candidate_version}")
|
493
498
|
target_version_array.push(candidate_version)
|
494
|
-
elsif version_compare(current_version, candidate_version) == 1
|
499
|
+
elsif !allow_downgrade && version_compare(current_version, candidate_version) == 1
|
495
500
|
logger.trace("#{new_resource} #{package_name} has installed version #{current_version}, which is newer than available version #{candidate_version}. Skipping...)")
|
496
501
|
target_version_array.push(nil)
|
497
502
|
else
|
@@ -666,7 +671,7 @@ class Chef
|
|
666
671
|
if new_resource.respond_to?("allow_downgrade")
|
667
672
|
new_resource.allow_downgrade
|
668
673
|
else
|
669
|
-
|
674
|
+
true
|
670
675
|
end
|
671
676
|
end
|
672
677
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
#
|
2
2
|
# Author:: Bryan McLellan <btm@loftninjas.org>
|
3
|
-
# Copyright:: Copyright 2014-
|
3
|
+
# Copyright:: Copyright 2014-2018, 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");
|
@@ -54,6 +54,16 @@ class Chef
|
|
54
54
|
@current_resource = Chef::Resource::WindowsPackage.new(new_resource.name)
|
55
55
|
if downloadable_file_missing?
|
56
56
|
logger.trace("We do not know the version of #{new_resource.source} because the file is not downloaded")
|
57
|
+
# FIXME: this label should not be used. It could be set to nil. Probably what should happen is that
|
58
|
+
# if the file hasn't been downloaded then load_current_resource must download the file here, and then
|
59
|
+
# the else clause to set current_resource.version can always be run. Relying on a side-effect here
|
60
|
+
# produces at least less readable code, if not outright buggy... (and I'm assuming that this isn't
|
61
|
+
# wholly just a bug -- since if we only need the package_name to determine if its installed then we
|
62
|
+
# need this, so I'm assuming we need to download the file to pull out the name in order to check
|
63
|
+
# the registry -- which it still feels like we get wrong in the sense we're forcing always downloading
|
64
|
+
# and then always installing(?) which violates idempotency -- and I'm having to think way too hard
|
65
|
+
# about this and would need to go surfing around the code to determine what actually happens, probably
|
66
|
+
# in every different package_provider...)
|
57
67
|
current_resource.version(:unknown.to_s)
|
58
68
|
else
|
59
69
|
current_resource.version(package_provider.installed_version)
|
@@ -164,6 +174,18 @@ class Chef
|
|
164
174
|
# this package provider does not support package arrays
|
165
175
|
# However, There may be multiple versions for a single
|
166
176
|
# package so the first element may be a nested array
|
177
|
+
#
|
178
|
+
# FIXME: this breaks the semantics of the superclass and needs to get unwound. Since these package
|
179
|
+
# providers don't support multipackage they can't put multiple versions into this array. The windows
|
180
|
+
# package managers need this in order to uninstall multiple installed version, and they should track
|
181
|
+
# that in something like an `uninstall_version_array` of their own. The superclass does not implement
|
182
|
+
# this kind of feature. Doing this here breaks LSP and will create bugs since the superclass will not
|
183
|
+
# expect it at all. The `current_resource.version` also MUST NOT be an array if the package provider
|
184
|
+
# is not multipackage. The existing implementation of package_provider.installed_version should probably
|
185
|
+
# be what `uninstall_version_array` is, and then that list should be sorted and last/first'd into the
|
186
|
+
# current_resource.version. The current_version_array method was not intended to be overwritten by
|
187
|
+
# sublasses (but ruby provides no feature to block doing so -- it is already marked as private).
|
188
|
+
#
|
167
189
|
def current_version_array
|
168
190
|
[ current_resource.version ]
|
169
191
|
end
|
@@ -125,8 +125,9 @@ def query(command):
|
|
125
125
|
# - in order to fix this, something would have to happen where getProvides was called first and
|
126
126
|
# then the result was searchNevra'd. please be extremely careful if attempting to fix that
|
127
127
|
# since searchNevra does not support prco tuples.
|
128
|
-
if
|
129
|
-
# handles flags (<, >, =, etc) and versions, but no wildcareds
|
128
|
+
if bool(re.search('\\s+', command['provides'])):
|
129
|
+
# handles flags (<, >, =, etc) and versions, but no wildcareds
|
130
|
+
# raises error for any invalid input like: 'FOO BAR BAZ'
|
130
131
|
pkgs = obj.getProvides(*string_to_prco_tuple(command['provides']))
|
131
132
|
elif do_nevra:
|
132
133
|
# now if we're given version or arch properties explicitly, then we do a SearchNevra.
|
@@ -109,7 +109,7 @@ class Chef
|
|
109
109
|
end
|
110
110
|
|
111
111
|
def install_package(name, version)
|
112
|
-
zypper_package("install", *options, "--auto-agree-with-licenses", allow_downgrade, name, version)
|
112
|
+
zypper_package("install", global_options, *options, "--auto-agree-with-licenses", allow_downgrade, name, version)
|
113
113
|
end
|
114
114
|
|
115
115
|
def upgrade_package(name, version)
|
@@ -118,19 +118,19 @@ class Chef
|
|
118
118
|
end
|
119
119
|
|
120
120
|
def remove_package(name, version)
|
121
|
-
zypper_package("remove", *options, name, version)
|
121
|
+
zypper_package("remove", global_options, *options, name, version)
|
122
122
|
end
|
123
123
|
|
124
124
|
def purge_package(name, version)
|
125
|
-
zypper_package("remove", *options, "--clean-deps", name, version)
|
125
|
+
zypper_package("remove", global_options, *options, "--clean-deps", name, version)
|
126
126
|
end
|
127
127
|
|
128
128
|
def lock_package(name, version)
|
129
|
-
zypper_package("addlock", *options, name, version)
|
129
|
+
zypper_package("addlock", global_options, *options, name, version)
|
130
130
|
end
|
131
131
|
|
132
132
|
def unlock_package(name, version)
|
133
|
-
zypper_package("removelock", *options, name, version)
|
133
|
+
zypper_package("removelock", global_options, *options, name, version)
|
134
134
|
end
|
135
135
|
|
136
136
|
private
|
@@ -141,12 +141,12 @@ class Chef
|
|
141
141
|
end
|
142
142
|
end
|
143
143
|
|
144
|
-
def zypper_package(command, *options, names, versions)
|
144
|
+
def zypper_package(command, global_options, *options, names, versions)
|
145
145
|
zipped_names = zip(names, versions)
|
146
146
|
if zypper_version < 1.0
|
147
|
-
shell_out!("zypper", gpg_checks, command, *options, "-y", names)
|
147
|
+
shell_out!("zypper", global_options, gpg_checks, command, *options, "-y", names)
|
148
148
|
else
|
149
|
-
shell_out!("zypper", "--non-interactive", gpg_checks, command, *options, zipped_names)
|
149
|
+
shell_out!("zypper", global_options, "--non-interactive", gpg_checks, command, *options, zipped_names)
|
150
150
|
end
|
151
151
|
end
|
152
152
|
|
@@ -157,6 +157,10 @@ class Chef
|
|
157
157
|
def allow_downgrade
|
158
158
|
"--oldpackage" if new_resource.allow_downgrade
|
159
159
|
end
|
160
|
+
|
161
|
+
def global_options
|
162
|
+
new_resource.global_options if new_resource.global_options
|
163
|
+
end
|
160
164
|
end
|
161
165
|
end
|
162
166
|
end
|
@@ -126,16 +126,22 @@ class Chef
|
|
126
126
|
value[:data] = value[:data].to_i
|
127
127
|
end
|
128
128
|
unless current_value[:type] == value[:type] && current_value[:data] == value[:data]
|
129
|
-
converge_by_value =
|
130
|
-
|
129
|
+
converge_by_value = if new_resource.sensitive
|
130
|
+
value.merge(data: "*sensitive value suppressed*")
|
131
|
+
else
|
132
|
+
value
|
133
|
+
end
|
131
134
|
|
132
135
|
converge_by("set value #{converge_by_value}") do
|
133
136
|
registry.set_value(new_resource.key, value)
|
134
137
|
end
|
135
138
|
end
|
136
139
|
else
|
137
|
-
converge_by_value =
|
138
|
-
|
140
|
+
converge_by_value = if new_resource.sensitive
|
141
|
+
value.merge(data: "*sensitive value suppressed*")
|
142
|
+
else
|
143
|
+
value
|
144
|
+
end
|
139
145
|
|
140
146
|
converge_by("set value #{converge_by_value}") do
|
141
147
|
registry.set_value(new_resource.key, value)
|
@@ -152,8 +158,11 @@ class Chef
|
|
152
158
|
end
|
153
159
|
new_resource.unscrubbed_values.each do |value|
|
154
160
|
unless @name_hash.key?(value[:name].downcase)
|
155
|
-
converge_by_value =
|
156
|
-
|
161
|
+
converge_by_value = if new_resource.sensitive
|
162
|
+
value.merge(data: "*sensitive value suppressed*")
|
163
|
+
else
|
164
|
+
value
|
165
|
+
end
|
157
166
|
|
158
167
|
converge_by("create value #{converge_by_value}") do
|
159
168
|
registry.set_value(new_resource.key, value)
|
@@ -39,12 +39,12 @@ class Chef
|
|
39
39
|
logger.warn("The 'gid' (or 'group') property is not implemented on the Windows platform. Please use the `members` property of the 'group' resource to assign a user to a group.")
|
40
40
|
end
|
41
41
|
|
42
|
-
@current_resource = Chef::Resource::User.new(new_resource.name)
|
42
|
+
@current_resource = Chef::Resource::User::WindowsUser.new(new_resource.name)
|
43
43
|
current_resource.username(new_resource.username)
|
44
44
|
begin
|
45
45
|
user_info = @net_user.get_info
|
46
|
-
|
47
46
|
current_resource.uid(user_info[:user_id])
|
47
|
+
current_resource.full_name(user_info[:full_name])
|
48
48
|
current_resource.comment(user_info[:comment])
|
49
49
|
current_resource.home(user_info[:home_dir])
|
50
50
|
current_resource.shell(user_info[:script_path])
|
@@ -67,7 +67,7 @@ class Chef
|
|
67
67
|
logger.trace("#{new_resource} password has changed")
|
68
68
|
return true
|
69
69
|
end
|
70
|
-
[ :uid, :comment, :home, :shell ].any? do |user_attrib|
|
70
|
+
[ :uid, :comment, :home, :shell, :full_name ].any? do |user_attrib|
|
71
71
|
!new_resource.send(user_attrib).nil? && new_resource.send(user_attrib) != current_resource.send(user_attrib)
|
72
72
|
end
|
73
73
|
end
|
@@ -100,6 +100,7 @@ class Chef
|
|
100
100
|
opts = { name: new_resource.username }
|
101
101
|
|
102
102
|
field_list = {
|
103
|
+
"full_name" => "full_name",
|
103
104
|
"comment" => "comment",
|
104
105
|
"home" => "home_dir",
|
105
106
|
"uid" => "user_id",
|
@@ -18,7 +18,7 @@
|
|
18
18
|
|
19
19
|
require "chef/mixin/shell_out"
|
20
20
|
require "rexml/document"
|
21
|
-
require "iso8601"
|
21
|
+
require "iso8601" if Chef::Platform.windows?
|
22
22
|
require "chef/mixin/powershell_out"
|
23
23
|
require "chef/provider"
|
24
24
|
require "chef/util/path_helper"
|
@@ -570,7 +570,16 @@ class Chef
|
|
570
570
|
def logon_type
|
571
571
|
# Ref: https://msdn.microsoft.com/en-us/library/windows/desktop/aa383566(v=vs.85).aspx
|
572
572
|
# if nothing is passed as logon_type the TASK_LOGON_SERVICE_ACCOUNT is getting set as default so using that for comparision.
|
573
|
-
new_resource.
|
573
|
+
user_id = new_resource.user
|
574
|
+
if Chef::ReservedNames::Win32::Security::SID.service_account_user?(user_id)
|
575
|
+
TaskScheduler::TASK_LOGON_SERVICE_ACCOUNT
|
576
|
+
elsif Chef::ReservedNames::Win32::Security::SID.group_user?(user_id)
|
577
|
+
TaskScheduler::TASK_LOGON_GROUP
|
578
|
+
elsif !new_resource.password.to_s.empty? # password is present
|
579
|
+
TaskScheduler::TASK_LOGON_PASSWORD
|
580
|
+
else
|
581
|
+
TaskScheduler::TASK_LOGON_INTERACTIVE_TOKEN
|
582
|
+
end
|
574
583
|
end
|
575
584
|
|
576
585
|
# This method checks if task and command properties exist since those two are mandatory properties to create a schedules task.
|
data/lib/chef/resource.rb
CHANGED
@@ -682,7 +682,7 @@ class Chef
|
|
682
682
|
Chef::JSONCompat.to_json(results, *a)
|
683
683
|
end
|
684
684
|
|
685
|
-
def
|
685
|
+
def to_h
|
686
686
|
# Grab all current state, then any other ivars (backcompat)
|
687
687
|
result = {}
|
688
688
|
self.class.state_properties.each do |p|
|
@@ -697,6 +697,8 @@ class Chef
|
|
697
697
|
result
|
698
698
|
end
|
699
699
|
|
700
|
+
alias_method :to_hash, :to_h
|
701
|
+
|
700
702
|
def self.from_hash(o)
|
701
703
|
resource = new(o["instance_vars"]["@name"])
|
702
704
|
o["instance_vars"].each do |k, v|
|
data/lib/chef/resource/locale.rb
CHANGED
@@ -61,7 +61,7 @@ class Chef
|
|
61
61
|
end
|
62
62
|
|
63
63
|
execute "reload root's lang profile script" do
|
64
|
-
command "source
|
64
|
+
command "source /etc/sysconfig/i18n; source /etc/profile.d/lang.sh"
|
65
65
|
not_if { updated }
|
66
66
|
end
|
67
67
|
elsif ::File.exist?("/usr/sbin/update-locale")
|
@@ -40,12 +40,12 @@ class Chef
|
|
40
40
|
action :create do
|
41
41
|
description "Create an Ohai hint file."
|
42
42
|
|
43
|
-
|
43
|
+
directory ::Ohai::Config.ohai.hints_path.first do
|
44
44
|
action :create
|
45
45
|
recursive true
|
46
46
|
end
|
47
47
|
|
48
|
-
|
48
|
+
file ohai_hint_file_path(new_resource.hint_name) do
|
49
49
|
action :create
|
50
50
|
content format_content(new_resource.content)
|
51
51
|
end
|
@@ -54,12 +54,12 @@ class Chef
|
|
54
54
|
action :delete do
|
55
55
|
description "Delete an Ohai hint file."
|
56
56
|
|
57
|
-
|
57
|
+
file ohai_hint_file_path(new_resource.hint_name) do
|
58
58
|
action :delete
|
59
59
|
notifies :reload, ohai[reload ohai post hint removal]
|
60
60
|
end
|
61
61
|
|
62
|
-
|
62
|
+
ohai "reload ohai post hint removal" do
|
63
63
|
action :nothing
|
64
64
|
end
|
65
65
|
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Kirill Kouznetsov <agon.smith@gmail.com>
|
3
|
+
#
|
4
|
+
# Copyright 2018, Kirill Kouznetsov.
|
5
|
+
# Copyright 2018, Chef Software, Inc.
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
#
|
19
|
+
|
20
|
+
require "chef/resource"
|
21
|
+
|
22
|
+
class Chef
|
23
|
+
class Resource
|
24
|
+
class Timezone < Chef::Resource
|
25
|
+
preview_resource true
|
26
|
+
resource_name :timezone
|
27
|
+
|
28
|
+
description "Use the timezone resource to change the system timezone."
|
29
|
+
introduced "14.6"
|
30
|
+
|
31
|
+
property :timezone, String,
|
32
|
+
description: "The timezone value to set.",
|
33
|
+
name_property: true
|
34
|
+
|
35
|
+
action :set do
|
36
|
+
description "Set the timezone."
|
37
|
+
|
38
|
+
package "tzdata" do
|
39
|
+
package_name platform_family?("suse") ? "timezone" : "tzdata"
|
40
|
+
end
|
41
|
+
|
42
|
+
if node["init_package"] == "systemd"
|
43
|
+
# Modern Amazon, Fedora, CentOS, RHEL, Ubuntu & Debian
|
44
|
+
cmd_set_tz = "/usr/bin/timedatectl --no-ask-password set-timezone #{new_resource.timezone}"
|
45
|
+
|
46
|
+
cmd_check_if_set = "/usr/bin/timedatectl status"
|
47
|
+
cmd_check_if_set += " | /usr/bin/awk '/Time.*zone/{print}'"
|
48
|
+
cmd_check_if_set += " | grep -q #{new_resource.timezone}"
|
49
|
+
|
50
|
+
execute cmd_set_tz do
|
51
|
+
action :run
|
52
|
+
not_if cmd_check_if_set
|
53
|
+
end
|
54
|
+
elsif platform_family?("rhel", "amazon")
|
55
|
+
# Old version of RHEL & CentOS
|
56
|
+
file "/etc/sysconfig/clock" do
|
57
|
+
owner "root"
|
58
|
+
group "root"
|
59
|
+
mode "0644"
|
60
|
+
action :create
|
61
|
+
content %{ZONE="#{new_resource.timezone}"\nUTC="true"\n}
|
62
|
+
end
|
63
|
+
|
64
|
+
execute "tzdata-update" do
|
65
|
+
command "/usr/sbin/tzdata-update"
|
66
|
+
action :nothing
|
67
|
+
only_if { ::File.executable?("/usr/sbin/tzdata-update") }
|
68
|
+
subscribes :run, "file[/etc/sysconfig/clock]", :immediately
|
69
|
+
end
|
70
|
+
|
71
|
+
link "/etc/localtime" do
|
72
|
+
to "/usr/share/zoneinfo/#{new_resource.timezone}"
|
73
|
+
not_if { ::File.executable?("/usr/sbin/tzdata-update") }
|
74
|
+
end
|
75
|
+
elsif platform_family?("debian")
|
76
|
+
file "/etc/timezone" do
|
77
|
+
action :create
|
78
|
+
content "#{new_resource.timezone}\n"
|
79
|
+
end
|
80
|
+
|
81
|
+
bash "dpkg-reconfigure tzdata" do
|
82
|
+
user "root"
|
83
|
+
code "/usr/sbin/dpkg-reconfigure -f noninteractive tzdata"
|
84
|
+
action :nothing
|
85
|
+
subscribes :run, "file[/etc/timezone]", :immediately
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -17,318 +17,320 @@
|
|
17
17
|
#
|
18
18
|
|
19
19
|
require "chef/resource"
|
20
|
+
require "chef/win32/security" if Chef::Platform.windows?
|
20
21
|
|
21
22
|
class Chef
|
22
23
|
class Resource
|
23
24
|
class WindowsTask < Chef::Resource
|
24
|
-
|
25
|
-
|
25
|
+
if Chef::Platform.windows?
|
26
|
+
resource_name :windows_task
|
27
|
+
provides(:windows_task) { true }
|
26
28
|
|
27
|
-
|
28
|
-
|
29
|
+
description "Use the windows_task resource to create, delete or run a Windows scheduled task. Requires Windows Server 2008 or later due to API usage."
|
30
|
+
introduced "13.0"
|
29
31
|
|
30
|
-
|
31
|
-
|
32
|
+
allowed_actions :create, :delete, :run, :end, :enable, :disable, :change
|
33
|
+
default_action :create
|
32
34
|
|
33
|
-
|
34
|
-
|
35
|
-
|
35
|
+
property :task_name, String, regex: [/\A[^\/\:\*\?\<\>\|]+\z/],
|
36
|
+
description: "The task name, such as 'Task Name' or '/Task Name'",
|
37
|
+
name_property: true
|
36
38
|
|
37
|
-
|
38
|
-
|
39
|
+
property :command, String,
|
40
|
+
description: "The command to be executed by the windows scheduled task."
|
39
41
|
|
40
|
-
|
41
|
-
|
42
|
+
property :cwd, String,
|
43
|
+
description: "The directory the task will be run from."
|
42
44
|
|
43
|
-
|
44
|
-
|
45
|
-
|
45
|
+
property :user, String,
|
46
|
+
description: "The user to run the task as.",
|
47
|
+
default: Chef::ReservedNames::Win32::Security::SID.LocalSystem.account_simple_name
|
46
48
|
|
47
|
-
|
48
|
-
|
49
|
+
property :password, String,
|
50
|
+
description: "The user’s password. The user property must be set if using this property."
|
49
51
|
|
50
|
-
|
51
|
-
|
52
|
-
|
52
|
+
property :run_level, Symbol, equal_to: [:highest, :limited],
|
53
|
+
description: "Run with ':limited' or ':highest' privileges.",
|
54
|
+
default: :limited
|
53
55
|
|
54
|
-
|
55
|
-
|
56
|
-
|
56
|
+
property :force, [TrueClass, FalseClass],
|
57
|
+
description: "When used with create, will update the task.",
|
58
|
+
default: false
|
57
59
|
|
58
|
-
|
59
|
-
|
60
|
-
|
60
|
+
property :interactive_enabled, [TrueClass, FalseClass],
|
61
|
+
description: "Allow task to run interactively or non-interactively. Requires user and password to also be set.",
|
62
|
+
default: false
|
61
63
|
|
62
|
-
|
63
|
-
|
64
|
+
property :frequency_modifier, [Integer, String],
|
65
|
+
default: 1
|
64
66
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
67
|
+
property :frequency, Symbol, equal_to: [:minute,
|
68
|
+
:hourly,
|
69
|
+
:daily,
|
70
|
+
:weekly,
|
71
|
+
:monthly,
|
72
|
+
:once,
|
73
|
+
:on_logon,
|
74
|
+
:onstart,
|
75
|
+
:on_idle,
|
76
|
+
:none],
|
77
|
+
description: "The frequency with which to run the task."
|
76
78
|
|
77
|
-
|
78
|
-
|
79
|
+
property :start_day, String,
|
80
|
+
description: "Specifies the first date on which the task runs in MM/DD/YYYY format."
|
79
81
|
|
80
|
-
|
81
|
-
|
82
|
+
property :start_time, String,
|
83
|
+
description: "Specifies the start time to run the task, in HH:mm format."
|
82
84
|
|
83
|
-
|
84
|
-
|
85
|
+
property :day, [String, Integer],
|
86
|
+
description: "The day(s) on which the task runs."
|
85
87
|
|
86
|
-
|
87
|
-
|
88
|
+
property :months, String,
|
89
|
+
description: "The Months of the year on which the task runs, such as: 'JAN, FEB' or '\*'. Multiple months should be comma delimited. e.g. 'Jan, Feb, Mar, Dec'."
|
88
90
|
|
89
|
-
|
90
|
-
|
91
|
+
property :idle_time, Integer,
|
92
|
+
description: "For :on_idle frequency, the time (in minutes) without user activity that must pass to trigger the task, from 1 - 999."
|
91
93
|
|
92
|
-
|
93
|
-
|
94
|
+
property :random_delay, [String, Integer],
|
95
|
+
description: "Delays the task up to a given time (in seconds)."
|
94
96
|
|
95
|
-
|
96
|
-
|
97
|
-
|
97
|
+
property :execution_time_limit, [String, Integer],
|
98
|
+
description: "The maximum time (in seconds) the task will run.",
|
99
|
+
default: "PT72H" # 72 hours in ISO8601 duration format
|
98
100
|
|
99
|
-
|
100
|
-
|
101
|
+
property :minutes_duration, [String, Integer],
|
102
|
+
description: ""
|
101
103
|
|
102
|
-
|
103
|
-
|
104
|
+
property :minutes_interval, [String, Integer],
|
105
|
+
description: ""
|
104
106
|
|
105
|
-
|
106
|
-
|
107
|
-
|
107
|
+
property :priority, Integer,
|
108
|
+
description: "Use to set Priority Levels range from 0 to 10.",
|
109
|
+
default: 7, callbacks: { "should be in range of 0 to 10" => proc { |v| v >= 0 && v <= 10 } }
|
108
110
|
|
109
|
-
|
110
|
-
|
111
|
-
|
111
|
+
property :disallow_start_if_on_batteries, [TrueClass, FalseClass],
|
112
|
+
introduced: "14.4", default: false,
|
113
|
+
description: "Disallow start of the task if the system is running on battery power."
|
112
114
|
|
113
|
-
|
114
|
-
|
115
|
-
|
115
|
+
property :stop_if_going_on_batteries, [TrueClass, FalseClass],
|
116
|
+
introduced: "14.4", default: false,
|
117
|
+
description: "Scheduled task option when system is switching on battery."
|
116
118
|
|
117
|
-
|
119
|
+
attr_accessor :exists, :task, :command_arguments
|
118
120
|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
VALID_WEEKS = %w{FIRST SECOND THIRD FOURTH LAST LASTDAY}.freeze
|
121
|
+
VALID_WEEK_DAYS = %w{ mon tue wed thu fri sat sun * }.freeze
|
122
|
+
VALID_DAYS_OF_MONTH = ("1".."31").to_a << "last" << "lastday"
|
123
|
+
VALID_MONTHS = %w{JAN FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC *}.freeze
|
124
|
+
VALID_WEEKS = %w{FIRST SECOND THIRD FOURTH LAST LASTDAY}.freeze
|
124
125
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
126
|
+
def after_created
|
127
|
+
if random_delay
|
128
|
+
validate_random_delay(random_delay, frequency)
|
129
|
+
random_delay(sec_to_min(random_delay))
|
130
|
+
end
|
130
131
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
132
|
+
if execution_time_limit
|
133
|
+
execution_time_limit(259200) if execution_time_limit == "PT72H"
|
134
|
+
raise ArgumentError, "Invalid value passed for `execution_time_limit`. Please pass seconds as an Integer (e.g. 60) or a String with numeric values only (e.g. '60')." unless numeric_value_in_string?(execution_time_limit)
|
135
|
+
execution_time_limit(sec_to_min(execution_time_limit))
|
136
|
+
end
|
136
137
|
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
138
|
+
validate_frequency(frequency) if action.include?(:create) || action.include?(:change)
|
139
|
+
validate_start_time(start_time, frequency)
|
140
|
+
validate_start_day(start_day, frequency) if start_day
|
141
|
+
validate_user_and_password(user, password)
|
142
|
+
validate_interactive_setting(interactive_enabled, password)
|
143
|
+
validate_create_frequency_modifier(frequency, frequency_modifier) if frequency_modifier
|
144
|
+
validate_create_day(day, frequency, frequency_modifier) if day
|
145
|
+
validate_create_months(months, frequency) if months
|
146
|
+
validate_frequency_monthly(frequency_modifier, months, day) if frequency == :monthly
|
147
|
+
validate_idle_time(idle_time, frequency)
|
148
|
+
idempotency_warning_for_frequency_weekly(day, start_day) if frequency == :weekly
|
149
|
+
end
|
149
150
|
|
150
|
-
|
151
|
+
private
|
151
152
|
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
153
|
+
## Resource is not idempotent when day, start_day is not provided with frequency :weekly
|
154
|
+
## we set start_day when not given by user as current date based on which we set the day property for current current date day is monday ..
|
155
|
+
## we set the monday as the day so at next run when new_resource.day is nil and current_resource day is monday due to which udpate gets called
|
156
|
+
def idempotency_warning_for_frequency_weekly(day, start_day)
|
157
|
+
if start_day.nil? && day.nil?
|
158
|
+
logger.warn "To maintain idempotency for frequency :weekly provide start_day, start_time and day."
|
159
|
+
end
|
158
160
|
end
|
159
|
-
end
|
160
161
|
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
162
|
+
# Validate the passed value is numeric values only if it is a string
|
163
|
+
def numeric_value_in_string?(val)
|
164
|
+
return true if Integer(val)
|
165
|
+
rescue ArgumentError
|
166
|
+
false
|
167
|
+
end
|
167
168
|
|
168
|
-
|
169
|
-
|
170
|
-
|
169
|
+
def validate_frequency(frequency)
|
170
|
+
if frequency.nil? || !([:minute, :hourly, :daily, :weekly, :monthly, :once, :on_logon, :onstart, :on_idle, :none].include?(frequency))
|
171
|
+
raise ArgumentError, "Frequency needs to be provided. Valid frequencies are :minute, :hourly, :daily, :weekly, :monthly, :once, :on_logon, :onstart, :on_idle, :none."
|
172
|
+
end
|
171
173
|
end
|
172
|
-
end
|
173
174
|
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
175
|
+
def validate_frequency_monthly(frequency_modifier, months, day)
|
176
|
+
# validates the frequency :monthly and raises error if frequency_modifier is first, second, thrid etc and day is not provided
|
177
|
+
if (frequency_modifier != 1) && (frequency_modifier_includes_days_of_weeks?(frequency_modifier)) && !(day)
|
178
|
+
raise ArgumentError, "Please select day on which you want to run the task e.g. 'Mon, Tue'. Multiple values must be seprated by comma."
|
179
|
+
end
|
180
|
+
|
181
|
+
# frequency_modifer 2-12 is used to set every (n) months, so using :months propety with frequency_modifer is not valid since they both used to set months.
|
182
|
+
# Not checking value 1 here for frequecy_modifier since we are setting that as default value it won't break anything since preference is given to months property
|
183
|
+
if (frequency_modifier.to_i.between?(2, 12)) && !(months.nil?)
|
184
|
+
raise ArgumentError, "For frequency :monthly either use property months or frequency_modifier to set months."
|
185
|
+
end
|
178
186
|
end
|
179
187
|
|
180
|
-
#
|
181
|
-
|
182
|
-
|
183
|
-
|
188
|
+
# returns true if frequency_modifer has values First, second, third, fourth, last, lastday
|
189
|
+
def frequency_modifier_includes_days_of_weeks?(frequency_modifier)
|
190
|
+
frequency_modifier = frequency_modifier.to_s.split(",")
|
191
|
+
frequency_modifier.map! { |value| value.strip.upcase }
|
192
|
+
(frequency_modifier - VALID_WEEKS).empty?
|
184
193
|
end
|
185
|
-
end
|
186
194
|
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
(frequency_modifier - VALID_WEEKS).empty?
|
192
|
-
end
|
195
|
+
def validate_random_delay(random_delay, frequency)
|
196
|
+
if [:on_logon, :onstart, :on_idle, :none].include? frequency
|
197
|
+
raise ArgumentError, "`random_delay` property is supported only for frequency :once, :minute, :hourly, :daily, :weekly and :monthly"
|
198
|
+
end
|
193
199
|
|
194
|
-
|
195
|
-
if [:on_logon, :onstart, :on_idle, :none].include? frequency
|
196
|
-
raise ArgumentError, "`random_delay` property is supported only for frequency :once, :minute, :hourly, :daily, :weekly and :monthly"
|
200
|
+
raise ArgumentError, "Invalid value passed for `random_delay`. Please pass seconds as an Integer (e.g. 60) or a String with numeric values only (e.g. '60')." unless numeric_value_in_string?(random_delay)
|
197
201
|
end
|
198
202
|
|
199
|
-
|
200
|
-
|
203
|
+
# @todo when we drop ruby 2.3 support this should be converted to .match?() instead of =~f
|
204
|
+
def validate_start_day(start_day, frequency)
|
205
|
+
if start_day && frequency == :none
|
206
|
+
raise ArgumentError, "`start_day` property is not supported with frequency: #{frequency}"
|
207
|
+
end
|
201
208
|
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
209
|
+
# make sure the start_day is in MM/DD/YYYY format: http://rubular.com/r/cgjHemtWl5
|
210
|
+
if start_day
|
211
|
+
raise ArgumentError, "`start_day` property must be in the MM/DD/YYYY format." unless /^(0[1-9]|1[012])[- \/.](0[1-9]|[12][0-9]|3[01])[- \/.](19|20)\d\d$/ =~ start_day
|
212
|
+
end
|
206
213
|
end
|
207
214
|
|
208
|
-
#
|
209
|
-
|
210
|
-
|
215
|
+
# @todo when we drop ruby 2.3 support this should be converted to .match?() instead of =~
|
216
|
+
def validate_start_time(start_time, frequency)
|
217
|
+
if start_time
|
218
|
+
raise ArgumentError, "`start_time` property is not supported with `frequency :none`" if frequency == :none
|
219
|
+
raise ArgumentError, "`start_time` property must be in the HH:mm format (e.g. 6:20pm -> 18:20)." unless /^[0-2][0-9]:[0-5][0-9]$/ =~ start_time
|
220
|
+
else
|
221
|
+
raise ArgumentError, "`start_time` needs to be provided with `frequency :once`" if frequency == :once
|
222
|
+
end
|
211
223
|
end
|
212
|
-
end
|
213
224
|
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
raise ArgumentError, "`start_time` property must be in the HH:mm format (e.g. 6:20pm -> 18:20)." unless /^[0-2][0-9]:[0-5][0-9]$/ =~ start_time
|
219
|
-
else
|
220
|
-
raise ArgumentError, "`start_time` needs to be provided with `frequency :once`" if frequency == :once
|
225
|
+
def validate_user_and_password(user, password)
|
226
|
+
if password_required?(user) && password.nil?
|
227
|
+
raise ArgumentError, "Cannot specify a user other than the system users without specifying a password!. Valid passwordless users: '#{Chef::ReservedNames::Win32::Security::SID::SYSTEM_USER.join("', '")}'"
|
228
|
+
end
|
221
229
|
end
|
222
|
-
end
|
223
230
|
|
224
|
-
|
225
|
-
|
226
|
-
|
231
|
+
def password_required?(user)
|
232
|
+
return false if user.nil?
|
233
|
+
@password_required ||= !Chef::ReservedNames::Win32::Security::SID.system_user?(user)
|
227
234
|
end
|
228
|
-
end
|
229
|
-
|
230
|
-
def password_required?(user)
|
231
|
-
return false if user.nil?
|
232
|
-
@password_required ||= !SYSTEM_USERS.include?(user.upcase)
|
233
|
-
end
|
234
235
|
|
235
|
-
|
236
|
-
|
237
|
-
end
|
238
|
-
|
239
|
-
def validate_create_frequency_modifier(frequency, frequency_modifier)
|
240
|
-
if ([:on_logon, :onstart, :on_idle, :none].include?(frequency)) && ( frequency_modifier != 1)
|
241
|
-
raise ArgumentError, "frequency_modifier property not supported with frequency :#{frequency}"
|
236
|
+
def validate_interactive_setting(interactive_enabled, password)
|
237
|
+
raise ArgumentError, "Please provide the password when attempting to set interactive/non-interactive." if interactive_enabled && password.nil?
|
242
238
|
end
|
243
239
|
|
244
|
-
|
245
|
-
|
246
|
-
raise ArgumentError, "frequency_modifier
|
240
|
+
def validate_create_frequency_modifier(frequency, frequency_modifier)
|
241
|
+
if ([:on_logon, :onstart, :on_idle, :none].include?(frequency)) && ( frequency_modifier != 1)
|
242
|
+
raise ArgumentError, "frequency_modifier property not supported with frequency :#{frequency}"
|
247
243
|
end
|
248
|
-
|
249
|
-
|
250
|
-
frequency_modifier
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
244
|
+
|
245
|
+
if frequency == :monthly
|
246
|
+
unless (1..12).cover?(frequency_modifier.to_i) || frequency_modifier_includes_days_of_weeks?(frequency_modifier)
|
247
|
+
raise ArgumentError, "frequency_modifier value #{frequency_modifier} is invalid. Valid values for :monthly frequency are 1 - 12, 'FIRST', 'SECOND', 'THIRD', 'FOURTH', 'LAST'."
|
248
|
+
end
|
249
|
+
else
|
250
|
+
unless frequency.nil? || frequency_modifier.nil?
|
251
|
+
frequency_modifier = frequency_modifier.to_i
|
252
|
+
min = 1
|
253
|
+
max = case frequency
|
254
|
+
when :minute
|
255
|
+
1439
|
256
|
+
when :hourly
|
257
|
+
23
|
258
|
+
when :daily
|
259
|
+
365
|
260
|
+
when :weekly
|
261
|
+
52
|
262
|
+
else
|
263
|
+
min
|
264
|
+
end
|
265
|
+
unless frequency_modifier.between?(min, max)
|
266
|
+
raise ArgumentError, "frequency_modifier value #{frequency_modifier} is invalid. Valid values for :#{frequency} frequency are #{min} - #{max}."
|
267
|
+
end
|
266
268
|
end
|
267
269
|
end
|
268
270
|
end
|
269
|
-
end
|
270
|
-
|
271
|
-
def validate_create_day(day, frequency, frequency_modifier)
|
272
|
-
raise ArgumentError, "day property is only valid for tasks that run monthly or weekly" unless [:weekly, :monthly].include?(frequency)
|
273
271
|
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
272
|
+
def validate_create_day(day, frequency, frequency_modifier)
|
273
|
+
raise ArgumentError, "day property is only valid for tasks that run monthly or weekly" unless [:weekly, :monthly].include?(frequency)
|
274
|
+
|
275
|
+
# This has been verified with schtask.exe https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/schtasks#d-dayday--
|
276
|
+
# verified with earlier code if day "*" is given with frequency it raised exception Invalid value for /D option
|
277
|
+
raise ArgumentError, "day wild card (*) is only valid with frequency :weekly" if frequency == :monthly && day == "*"
|
278
|
+
|
279
|
+
if day.is_a?(String) && day.to_i.to_s != day
|
280
|
+
days = day.split(",")
|
281
|
+
if days_includes_days_of_months?(days)
|
282
|
+
# Following error will be raise if day is set as 1-31 and frequency is selected as :weekly since those values are valid with only frequency :monthly
|
283
|
+
raise ArgumentError, "day values 1-31 or last is only valid with frequency :monthly" if frequency == :weekly
|
284
|
+
else
|
285
|
+
days.map! { |day| day.to_s.strip.downcase }
|
286
|
+
unless (days - VALID_WEEK_DAYS).empty?
|
287
|
+
raise ArgumentError, "day property invalid. Only valid values are: #{VALID_WEEK_DAYS.map(&:upcase).join(', ')}. Multiple values must be separated by a comma."
|
288
|
+
end
|
287
289
|
end
|
288
290
|
end
|
289
291
|
end
|
290
|
-
end
|
291
292
|
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
293
|
+
def validate_create_months(months, frequency)
|
294
|
+
raise ArgumentError, "months property is only valid for tasks that run monthly" if frequency != :monthly
|
295
|
+
if months.is_a?(String)
|
296
|
+
months = months.split(",")
|
297
|
+
months.map! { |month| month.strip.upcase }
|
298
|
+
unless (months - VALID_MONTHS).empty?
|
299
|
+
raise ArgumentError, "months property invalid. Only valid values are: #{VALID_MONTHS.join(', ')}. Multiple values must be separated by a comma."
|
300
|
+
end
|
299
301
|
end
|
300
302
|
end
|
301
|
-
end
|
302
|
-
|
303
|
-
# This method returns true if day has values from 1-31 which is a days of moths and used with frequency :monthly
|
304
|
-
def days_includes_days_of_months?(days)
|
305
|
-
days.map! { |day| day.to_s.strip.downcase }
|
306
|
-
(days - VALID_DAYS_OF_MONTH).empty?
|
307
|
-
end
|
308
303
|
|
309
|
-
|
310
|
-
|
311
|
-
|
304
|
+
# This method returns true if day has values from 1-31 which is a days of moths and used with frequency :monthly
|
305
|
+
def days_includes_days_of_months?(days)
|
306
|
+
days.map! { |day| day.to_s.strip.downcase }
|
307
|
+
(days - VALID_DAYS_OF_MONTH).empty?
|
312
308
|
end
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
309
|
+
|
310
|
+
def validate_idle_time(idle_time, frequency)
|
311
|
+
if !idle_time.nil? && frequency != :on_idle
|
312
|
+
raise ArgumentError, "idle_time property is only valid for tasks that run on_idle"
|
313
|
+
end
|
314
|
+
if idle_time.nil? && frequency == :on_idle
|
315
|
+
raise ArgumentError, "idle_time value should be set for :on_idle frequency."
|
316
|
+
end
|
317
|
+
unless idle_time.nil? || idle_time > 0 && idle_time <= 999
|
318
|
+
raise ArgumentError, "idle_time value #{idle_time} is invalid. Valid values for :on_idle frequency are 1 - 999."
|
319
|
+
end
|
318
320
|
end
|
319
|
-
end
|
320
321
|
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
322
|
+
# Converts the number of seconds to an ISO8601 duration format and returns it.
|
323
|
+
# Ref : https://github.com/arnau/ISO8601/blob/master/lib/iso8601/duration.rb#L18-L23
|
324
|
+
# e.g.
|
325
|
+
# ISO8601::Duration.new(65707200).to_s
|
326
|
+
# returns 'PT65707200S'
|
327
|
+
def sec_to_dur(seconds)
|
328
|
+
ISO8601::Duration.new(seconds.to_i).to_s
|
329
|
+
end
|
329
330
|
|
330
|
-
|
331
|
-
|
331
|
+
def sec_to_min(seconds)
|
332
|
+
seconds.to_i / 60
|
333
|
+
end
|
332
334
|
end
|
333
335
|
end
|
334
336
|
end
|