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.
Files changed (98) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +5 -3
  3. data/chef-universal-mingw32.gemspec +3 -2
  4. data/chef.gemspec +3 -4
  5. data/lib/chef/api_client.rb +5 -3
  6. data/lib/chef/api_client_v1.rb +6 -4
  7. data/lib/chef/application.rb +1 -1
  8. data/lib/chef/audit/audit_reporter.rb +1 -1
  9. data/lib/chef/audit/control_group_data.rb +12 -6
  10. data/lib/chef/chef_fs/chef_fs_data_store.rb +2 -2
  11. data/lib/chef/chef_fs/data_handler/data_handler_base.rb +1 -1
  12. data/lib/chef/cookbook/manifest_v0.rb +34 -29
  13. data/lib/chef/cookbook/manifest_v2.rb +15 -11
  14. data/lib/chef/cookbook/metadata.rb +4 -2
  15. data/lib/chef/cookbook_manifest.rb +8 -5
  16. data/lib/chef/cookbook_version.rb +1 -1
  17. data/lib/chef/data_bag.rb +4 -2
  18. data/lib/chef/data_bag_item.rb +5 -3
  19. data/lib/chef/data_collector.rb +2 -2
  20. data/lib/chef/data_collector/resource_report.rb +4 -4
  21. data/lib/chef/encrypted_data_bag_item.rb +4 -2
  22. data/lib/chef/environment.rb +4 -2
  23. data/lib/chef/file_content_management/deploy/mv_unix.rb +5 -4
  24. data/lib/chef/handler.rb +2 -2
  25. data/lib/chef/json_compat.rb +1 -1
  26. data/lib/chef/key.rb +7 -5
  27. data/lib/chef/knife/bootstrap.rb +7 -1
  28. data/lib/chef/knife/client_edit.rb +2 -2
  29. data/lib/chef/knife/data_bag_show.rb +2 -2
  30. data/lib/chef/knife/osc_user_edit.rb +2 -2
  31. data/lib/chef/knife/user_edit.rb +2 -2
  32. data/lib/chef/mixin/params_validate.rb +4 -2
  33. data/lib/chef/node/attribute.rb +4 -4
  34. data/lib/chef/org.rb +6 -4
  35. data/lib/chef/policy_builder/policyfile.rb +5 -3
  36. data/lib/chef/provider/package.rb +9 -4
  37. data/lib/chef/provider/package/windows.rb +23 -1
  38. data/lib/chef/provider/package/yum/yum_helper.py +3 -2
  39. data/lib/chef/provider/package/zypper.rb +12 -8
  40. data/lib/chef/provider/registry_key.rb +15 -6
  41. data/lib/chef/provider/user/windows.rb +4 -3
  42. data/lib/chef/provider/windows_task.rb +11 -2
  43. data/lib/chef/resource.rb +3 -1
  44. data/lib/chef/resource/locale.rb +1 -1
  45. data/lib/chef/resource/ohai_hint.rb +4 -4
  46. data/lib/chef/resource/rhsm_errata_level.rb +1 -1
  47. data/lib/chef/resource/timezone.rb +91 -0
  48. data/lib/chef/resource/user/windows_user.rb +4 -0
  49. data/lib/chef/resource/windows_task.rb +240 -238
  50. data/lib/chef/resource/zypper_package.rb +5 -0
  51. data/lib/chef/resource_collection/resource_collection_serialization.rb +4 -2
  52. data/lib/chef/resources.rb +1 -0
  53. data/lib/chef/role.rb +4 -2
  54. data/lib/chef/run_list/run_list_expansion.rb +5 -3
  55. data/lib/chef/run_status.rb +4 -2
  56. data/lib/chef/user.rb +7 -5
  57. data/lib/chef/user_v1.rb +8 -6
  58. data/lib/chef/version.rb +1 -1
  59. data/lib/chef/win32/security/sid.rb +39 -0
  60. data/spec/functional/assets/zypprepo/chef_rpm-1.10-1.aarch64.rpm +0 -0
  61. data/spec/functional/assets/zypprepo/chef_rpm-1.10-1.i686.rpm +0 -0
  62. data/spec/functional/assets/zypprepo/chef_rpm-1.10-1.ppc64.rpm +0 -0
  63. data/spec/functional/assets/zypprepo/chef_rpm-1.10-1.ppc64le.rpm +0 -0
  64. data/spec/functional/assets/zypprepo/chef_rpm-1.10-1.s390x.rpm +0 -0
  65. data/spec/functional/assets/zypprepo/chef_rpm-1.10-1.src.rpm +0 -0
  66. data/spec/functional/assets/zypprepo/chef_rpm-1.10-1.x86_64.rpm +0 -0
  67. data/spec/functional/assets/zypprepo/chef_rpm-1.2-1.aarch64.rpm +0 -0
  68. data/spec/functional/assets/zypprepo/chef_rpm-1.2-1.i686.rpm +0 -0
  69. data/spec/functional/assets/zypprepo/chef_rpm-1.2-1.ppc64.rpm +0 -0
  70. data/spec/functional/assets/zypprepo/chef_rpm-1.2-1.ppc64le.rpm +0 -0
  71. data/spec/functional/assets/zypprepo/chef_rpm-1.2-1.s390x.rpm +0 -0
  72. data/spec/functional/assets/zypprepo/chef_rpm-1.2-1.src.rpm +0 -0
  73. data/spec/functional/assets/zypprepo/chef_rpm-1.2-1.x86_64.rpm +0 -0
  74. data/spec/functional/http/simple_spec.rb +2 -2
  75. data/spec/functional/resource/remote_file_spec.rb +2 -2
  76. data/spec/functional/resource/user/windows_spec.rb +1 -1
  77. data/spec/functional/resource/windows_task_spec.rb +1 -1
  78. data/spec/functional/resource/zypper_package_spec.rb +233 -0
  79. data/spec/spec_helper.rb +1 -0
  80. data/spec/unit/audit/audit_reporter_spec.rb +4 -4
  81. data/spec/unit/audit/control_group_data_spec.rb +17 -17
  82. data/spec/unit/environment_spec.rb +1 -1
  83. data/spec/unit/file_content_management/deploy/mv_unix_spec.rb +13 -1
  84. data/spec/unit/node_spec.rb +33 -0
  85. data/spec/unit/provider/package/rpm_spec.rb +5 -5
  86. data/spec/unit/provider/package/zypper_spec.rb +51 -0
  87. data/spec/unit/provider/package_spec.rb +32 -2
  88. data/spec/unit/provider/registry_key_spec.rb +74 -0
  89. data/spec/unit/provider/user/windows_spec.rb +12 -3
  90. data/spec/unit/provider/windows_task_spec.rb +1 -0
  91. data/spec/unit/resource/timezone.rb +39 -0
  92. data/spec/unit/resource/windows_task_spec.rb +1 -1
  93. data/spec/unit/resource_collection_spec.rb +1 -1
  94. data/spec/unit/run_context/child_run_context_spec.rb +3 -3
  95. data/spec/unit/shell/shell_session_spec.rb +3 -2
  96. metadata +37 -41
  97. data/CONTRIBUTING.md +0 -152
  98. 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 && !allow_downgrade
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
- false
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-2016, Chef Software, Inc.
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 any(elem in command['provides'] for elem in r"<=>"):
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 = value
130
- converge_by_value[:data] = "*sensitive value suppressed*" if new_resource.sensitive
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 = value
138
- converge_by_value[:data] = "*sensitive value suppressed*" if new_resource.sensitive
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 = value
156
- converge_by_value[:data] = "*sensitive value suppressed*" if new_resource.sensitive
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.password.nil? ? TaskScheduler::TASK_LOGON_SERVICE_ACCOUNT : TaskScheduler::TASK_LOGON_PASSWORD
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.
@@ -682,7 +682,7 @@ class Chef
682
682
  Chef::JSONCompat.to_json(results, *a)
683
683
  end
684
684
 
685
- def to_hash
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|
@@ -61,7 +61,7 @@ class Chef
61
61
  end
62
62
 
63
63
  execute "reload root's lang profile script" do
64
- command "source source /etc/sysconfig/i18n; source /etc/profile.d/lang.sh"
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
- declare_resource(:directory, ::Ohai::Config.ohai.hints_path.first) do
43
+ directory ::Ohai::Config.ohai.hints_path.first do
44
44
  action :create
45
45
  recursive true
46
46
  end
47
47
 
48
- declare_resource(:file, ohai_hint_file_path(new_resource.hint_name)) do
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
- declare_resource(:file, ohai_hint_file_path(new_resource.hint_name)) do
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
- declare_resource(:ohai, "reload ohai post hint removal") do
62
+ ohai "reload ohai post hint removal" do
63
63
  action :nothing
64
64
  end
65
65
  end
@@ -33,7 +33,7 @@ class Chef
33
33
  name_property: true
34
34
 
35
35
  action :install do
36
- descripton "Install all packages of the specified errata level."
36
+ description "Install all packages of the specified errata level."
37
37
 
38
38
  yum_package "yum-plugin-security" do
39
39
  action :install
@@ -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
@@ -25,6 +25,10 @@ class Chef
25
25
 
26
26
  provides :windows_user
27
27
  provides :user, os: "windows"
28
+
29
+ property :full_name, String,
30
+ description: "The full name of the user.",
31
+ introduced: "14.6"
28
32
  end
29
33
  end
30
34
  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
- resource_name :windows_task
25
- provides(:windows_task) { true }
25
+ if Chef::Platform.windows?
26
+ resource_name :windows_task
27
+ provides(:windows_task) { true }
26
28
 
27
- 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."
28
- introduced "13.0"
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
- allowed_actions :create, :delete, :run, :end, :enable, :disable, :change
31
- default_action :create
32
+ allowed_actions :create, :delete, :run, :end, :enable, :disable, :change
33
+ default_action :create
32
34
 
33
- property :task_name, String, regex: [/\A[^\/\:\*\?\<\>\|]+\z/],
34
- description: "The task name, such as 'Task Name' or '/Task Name'",
35
- name_property: true
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
- property :command, String,
38
- description: "The command to be executed by the windows scheduled task."
39
+ property :command, String,
40
+ description: "The command to be executed by the windows scheduled task."
39
41
 
40
- property :cwd, String,
41
- description: "The directory the task will be run from."
42
+ property :cwd, String,
43
+ description: "The directory the task will be run from."
42
44
 
43
- property :user, String,
44
- description: "The user to run the task as.",
45
- default: "SYSTEM"
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
- property :password, String,
48
- description: "The user’s password. The user property must be set if using this property."
49
+ property :password, String,
50
+ description: "The user’s password. The user property must be set if using this property."
49
51
 
50
- property :run_level, Symbol, equal_to: [:highest, :limited],
51
- description: "Run with ':limited' or ':highest' privileges.",
52
- default: :limited
52
+ property :run_level, Symbol, equal_to: [:highest, :limited],
53
+ description: "Run with ':limited' or ':highest' privileges.",
54
+ default: :limited
53
55
 
54
- property :force, [TrueClass, FalseClass],
55
- description: "When used with create, will update the task.",
56
- default: false
56
+ property :force, [TrueClass, FalseClass],
57
+ description: "When used with create, will update the task.",
58
+ default: false
57
59
 
58
- property :interactive_enabled, [TrueClass, FalseClass],
59
- description: "Allow task to run interactively or non-interactively. Requires user and password to also be set.",
60
- default: false
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
- property :frequency_modifier, [Integer, String],
63
- default: 1
64
+ property :frequency_modifier, [Integer, String],
65
+ default: 1
64
66
 
65
- property :frequency, Symbol, equal_to: [:minute,
66
- :hourly,
67
- :daily,
68
- :weekly,
69
- :monthly,
70
- :once,
71
- :on_logon,
72
- :onstart,
73
- :on_idle,
74
- :none],
75
- description: "The frequency with which to run the task."
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
- property :start_day, String,
78
- description: "Specifies the first date on which the task runs in MM/DD/YYYY format."
79
+ property :start_day, String,
80
+ description: "Specifies the first date on which the task runs in MM/DD/YYYY format."
79
81
 
80
- property :start_time, String,
81
- description: "Specifies the start time to run the task, in HH:mm format."
82
+ property :start_time, String,
83
+ description: "Specifies the start time to run the task, in HH:mm format."
82
84
 
83
- property :day, [String, Integer],
84
- description: "The day(s) on which the task runs."
85
+ property :day, [String, Integer],
86
+ description: "The day(s) on which the task runs."
85
87
 
86
- property :months, String,
87
- 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
+ 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
- property :idle_time, Integer,
90
- description: "For :on_idle frequency, the time (in minutes) without user activity that must pass to trigger the task, from 1 - 999."
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
- property :random_delay, [String, Integer],
93
- description: "Delays the task up to a given time (in seconds)."
94
+ property :random_delay, [String, Integer],
95
+ description: "Delays the task up to a given time (in seconds)."
94
96
 
95
- property :execution_time_limit, [String, Integer],
96
- description: "The maximum time (in seconds) the task will run.",
97
- default: "PT72H" # 72 hours in ISO8601 duration format
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
- property :minutes_duration, [String, Integer],
100
- description: ""
101
+ property :minutes_duration, [String, Integer],
102
+ description: ""
101
103
 
102
- property :minutes_interval, [String, Integer],
103
- description: ""
104
+ property :minutes_interval, [String, Integer],
105
+ description: ""
104
106
 
105
- property :priority, Integer,
106
- description: "Use to set Priority Levels range from 0 to 10.",
107
- default: 7, callbacks: { "should be in range of 0 to 10" => proc { |v| v >= 0 && v <= 10 } }
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
- property :disallow_start_if_on_batteries, [TrueClass, FalseClass],
110
- introduced: "14.4", default: false,
111
- description: "Disallow start of the task if the system is running on battery power."
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
- property :stop_if_going_on_batteries, [TrueClass, FalseClass],
114
- introduced: "14.4", default: false,
115
- description: "Scheduled task option when system is switching on battery."
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
- attr_accessor :exists, :task, :command_arguments
119
+ attr_accessor :exists, :task, :command_arguments
118
120
 
119
- SYSTEM_USERS = ['NT AUTHORITY\SYSTEM', "SYSTEM", 'NT AUTHORITY\LOCALSERVICE', 'NT AUTHORITY\NETWORKSERVICE', 'BUILTIN\USERS', "USERS"].freeze
120
- VALID_WEEK_DAYS = %w{ mon tue wed thu fri sat sun * }.freeze
121
- VALID_DAYS_OF_MONTH = ("1".."31").to_a << "last" << "lastday"
122
- VALID_MONTHS = %w{JAN FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC *}.freeze
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
- def after_created
126
- if random_delay
127
- validate_random_delay(random_delay, frequency)
128
- random_delay(sec_to_min(random_delay))
129
- end
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
- if execution_time_limit
132
- execution_time_limit(259200) if execution_time_limit == "PT72H"
133
- 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)
134
- execution_time_limit(sec_to_min(execution_time_limit))
135
- end
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
- validate_frequency(frequency) if action.include?(:create) || action.include?(:change)
138
- validate_start_time(start_time, frequency)
139
- validate_start_day(start_day, frequency) if start_day
140
- validate_user_and_password(user, password)
141
- validate_interactive_setting(interactive_enabled, password)
142
- validate_create_frequency_modifier(frequency, frequency_modifier) if frequency_modifier
143
- validate_create_day(day, frequency, frequency_modifier) if day
144
- validate_create_months(months, frequency) if months
145
- validate_frequency_monthly(frequency_modifier, months, day) if frequency == :monthly
146
- validate_idle_time(idle_time, frequency)
147
- idempotency_warning_for_frequency_weekly(day, start_day) if frequency == :weekly
148
- end
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
- private
151
+ private
151
152
 
152
- ## Resource is not idempotent when day, start_day is not provided with frequency :weekly
153
- ## 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 ..
154
- ## 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
155
- def idempotency_warning_for_frequency_weekly(day, start_day)
156
- if start_day.nil? && day.nil?
157
- logger.warn "To maintain idempotency for frequency :weekly provide start_day, start_time and day."
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
- # Validate the passed value is numeric values only if it is a string
162
- def numeric_value_in_string?(val)
163
- return true if Integer(val)
164
- rescue ArgumentError
165
- false
166
- end
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
- def validate_frequency(frequency)
169
- if frequency.nil? || !([:minute, :hourly, :daily, :weekly, :monthly, :once, :on_logon, :onstart, :on_idle, :none].include?(frequency))
170
- raise ArgumentError, "Frequency needs to be provided. Valid frequencies are :minute, :hourly, :daily, :weekly, :monthly, :once, :on_logon, :onstart, :on_idle, :none."
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
- def validate_frequency_monthly(frequency_modifier, months, day)
175
- # validates the frequency :monthly and raises error if frequency_modifier is first, second, thrid etc and day is not provided
176
- if (frequency_modifier != 1) && (frequency_modifier_includes_days_of_weeks?(frequency_modifier)) && !(day)
177
- raise ArgumentError, "Please select day on which you want to run the task e.g. 'Mon, Tue'. Multiple values must be seprated by comma."
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
- # 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.
181
- # 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
182
- if (frequency_modifier.to_i.between?(2, 12)) && !(months.nil?)
183
- raise ArgumentError, "For frequency :monthly either use property months or frequency_modifier to set months."
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
- # returns true if frequency_modifer has values First, second, third, fourth, last, lastday
188
- def frequency_modifier_includes_days_of_weeks?(frequency_modifier)
189
- frequency_modifier = frequency_modifier.to_s.split(",")
190
- frequency_modifier.map! { |value| value.strip.upcase }
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
- def validate_random_delay(random_delay, frequency)
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
- 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)
200
- end
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
- # @todo when we drop ruby 2.3 support this should be converted to .match?() instead of =~f
203
- def validate_start_day(start_day, frequency)
204
- if start_day && frequency == :none
205
- raise ArgumentError, "`start_day` property is not supported with frequency: #{frequency}"
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
- # make sure the start_day is in MM/DD/YYYY format: http://rubular.com/r/cgjHemtWl5
209
- if start_day
210
- 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
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
- # @todo when we drop ruby 2.3 support this should be converted to .match?() instead of =~
215
- def validate_start_time(start_time, frequency)
216
- if start_time
217
- raise ArgumentError, "`start_time` property is not supported with `frequency :none`" if frequency == :none
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
- def validate_user_and_password(user, password)
225
- if password_required?(user) && password.nil?
226
- raise ArgumentError, %q{Cannot specify a user other than the system users without specifying a password!. Valid passwordless users: 'NT AUTHORITY\SYSTEM', 'SYSTEM', 'NT AUTHORITY\LOCALSERVICE', 'NT AUTHORITY\NETWORKSERVICE', 'BUILTIN\USERS', 'USERS'}
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
- def validate_interactive_setting(interactive_enabled, password)
236
- raise ArgumentError, "Please provide the password when attempting to set interactive/non-interactive." if interactive_enabled && password.nil?
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
- if frequency == :monthly
245
- unless (1..12).cover?(frequency_modifier.to_i) || frequency_modifier_includes_days_of_weeks?(frequency_modifier)
246
- raise ArgumentError, "frequency_modifier value #{frequency_modifier} is invalid. Valid values for :monthly frequency are 1 - 12, 'FIRST', 'SECOND', 'THIRD', 'FOURTH', 'LAST'."
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
- else
249
- unless frequency.nil? || frequency_modifier.nil?
250
- frequency_modifier = frequency_modifier.to_i
251
- min = 1
252
- max = case frequency
253
- when :minute
254
- 1439
255
- when :hourly
256
- 23
257
- when :daily
258
- 365
259
- when :weekly
260
- 52
261
- else
262
- min
263
- end
264
- unless frequency_modifier.between?(min, max)
265
- raise ArgumentError, "frequency_modifier value #{frequency_modifier} is invalid. Valid values for :#{frequency} frequency are #{min} - #{max}."
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
- # This has been verified with schtask.exe https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/schtasks#d-dayday--
275
- # verified with earlier code if day "*" is given with frequency it raised exception Invalid value for /D option
276
- raise ArgumentError, "day wild card (*) is only valid with frequency :weekly" if frequency == :monthly && day == "*"
277
-
278
- if day.is_a?(String) && day.to_i.to_s != day
279
- days = day.split(",")
280
- if days_includes_days_of_months?(days)
281
- # 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
282
- raise ArgumentError, "day values 1-31 or last is only valid with frequency :monthly" if frequency == :weekly
283
- else
284
- days.map! { |day| day.to_s.strip.downcase }
285
- unless (days - VALID_WEEK_DAYS).empty?
286
- raise ArgumentError, "day property invalid. Only valid values are: #{VALID_WEEK_DAYS.map(&:upcase).join(', ')}. Multiple values must be separated by a comma."
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
- def validate_create_months(months, frequency)
293
- raise ArgumentError, "months property is only valid for tasks that run monthly" if frequency != :monthly
294
- if months.is_a?(String)
295
- months = months.split(",")
296
- months.map! { |month| month.strip.upcase }
297
- unless (months - VALID_MONTHS).empty?
298
- raise ArgumentError, "months property invalid. Only valid values are: #{VALID_MONTHS.join(', ')}. Multiple values must be separated by a comma."
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
- def validate_idle_time(idle_time, frequency)
310
- if !idle_time.nil? && frequency != :on_idle
311
- raise ArgumentError, "idle_time property is only valid for tasks that run on_idle"
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
- if idle_time.nil? && frequency == :on_idle
314
- raise ArgumentError, "idle_time value should be set for :on_idle frequency."
315
- end
316
- unless idle_time.nil? || idle_time > 0 && idle_time <= 999
317
- raise ArgumentError, "idle_time value #{idle_time} is invalid. Valid values for :on_idle frequency are 1 - 999."
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
- # Converts the number of seconds to an ISO8601 duration format and returns it.
322
- # Ref : https://github.com/arnau/ISO8601/blob/master/lib/iso8601/duration.rb#L18-L23
323
- # e.g.
324
- # ISO8601::Duration.new(65707200).to_s
325
- # returns 'PT65707200S'
326
- def sec_to_dur(seconds)
327
- ISO8601::Duration.new(seconds.to_i).to_s
328
- end
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
- def sec_to_min(seconds)
331
- seconds.to_i / 60
331
+ def sec_to_min(seconds)
332
+ seconds.to_i / 60
333
+ end
332
334
  end
333
335
  end
334
336
  end