chef 14.5.33-universal-mingw32 → 14.6.47-universal-mingw32

Sign up to get free protection for your applications and to get access to all the features.
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