summaryrefslogtreecommitdiff
path: root/lib/chef/resource/windows_task.rb
diff options
context:
space:
mode:
authorVasu1105 <vasundhara.jagdale@msystechnologies.com>2018-01-31 11:47:09 +0000
committervasu1105 <vasundhara.jagdale@msystechnologies.com>2018-04-24 11:32:31 +0530
commit2c665b3e889381062b2faf1f28d4a41ca1a698cb (patch)
tree2d8e1fdc98a9d267c6fa403732d421e6feb6d684 /lib/chef/resource/windows_task.rb
parent5ef14cc77226fe16b734ec90aead1de5d49ca7fb (diff)
downloadchef-2c665b3e889381062b2faf1f28d4a41ca1a698cb.tar.gz
[MSYS-752] windows task rewrite using wind32-taskscheduler
Signed-off-by: Vasu1105 <vasundhara.jagdale@msystechnologies.com>
Diffstat (limited to 'lib/chef/resource/windows_task.rb')
-rw-r--r--lib/chef/resource/windows_task.rb180
1 files changed, 123 insertions, 57 deletions
diff --git a/lib/chef/resource/windows_task.rb b/lib/chef/resource/windows_task.rb
index 8b4743eecc..38f651d670 100644
--- a/lib/chef/resource/windows_task.rb
+++ b/lib/chef/resource/windows_task.rb
@@ -28,7 +28,7 @@ class Chef
" scheduled task. Requires Windows Server 2008 or later due to API usage."
introduced "13.0"
- allowed_actions :create, :delete, :run, :end, :enable, :disable
+ allowed_actions :create, :delete, :run, :end, :enable, :disable, :change
default_action :create
property :task_name, String, regex: [/\A[^\/\:\*\?\<\>\|]+\z/], name_property: true
@@ -49,7 +49,7 @@ class Chef
:on_logon,
:onstart,
:on_idle,
- :none], default: :hourly
+ :none]
property :start_day, String
property :start_time, String
property :day, [String, Integer]
@@ -57,36 +57,59 @@ class Chef
property :idle_time, Integer
property :random_delay, [String, Integer]
property :execution_time_limit, [String, Integer], default: "PT72H" # 72 hours in ISO8601 duration format
+ property :minutes_duration, [String, Integer]
+ property :minutes_interval, [String, Integer]
- attr_accessor :exists, :status, :enabled
+ attr_accessor :exists, :task
+
+ SYSTEM_USERS = ['NT AUTHORITY\SYSTEM', "SYSTEM", 'NT AUTHORITY\LOCALSERVICE', 'NT AUTHORITY\NETWORKSERVICE', 'BUILTIN\USERS', "USERS"].freeze
+ VALID_WEEK_DAYS = %w{ mon tue wed thu fri sat sun * }
+ VALID_DAYS_OF_MONTH = ("1".."31").to_a << "last" << "lastday"
+ VALID_MONTHS = %w{JAN FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC *}
+ VALID_WEEKS = %w{FIRST SECOND THIRD FOURTH LAST LASTDAY}
def after_created
if random_delay
validate_random_delay(random_delay, frequency)
- duration = sec_to_dur(random_delay)
- random_delay(duration)
+ random_delay(sec_to_min(random_delay))
end
if execution_time_limit
- unless execution_time_limit == "PT72H" # don't double convert an ISO8601 format duration
- 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)
- duration = sec_to_dur(execution_time_limit)
- execution_time_limit(duration)
- end
+ execution_time_limit(259200) if execution_time_limit == "PT72H"
+ 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)
+ execution_time_limit(sec_to_min(execution_time_limit))
end
+ # Removed the default value :hourly for frequency in Chef 14 following code added for backward compatibility
+ chef_version = ::Chef::VERSION.split(".")
+ if chef_version[0].to_i > 13 || (chef_version[0].to_i >= 0)
+ validate_frequency(frequency) if action.include?(:create) || action.include?(:change)
+ else
+ frequency(:hourly) if frequency.nil?
+ end
validate_start_time(start_time, frequency)
validate_start_day(start_day, frequency) if start_day
validate_user_and_password(user, password)
validate_interactive_setting(interactive_enabled, password)
- validate_create_frequency_modifier(frequency, frequency_modifier)
- validate_create_day(day, frequency) if day
+ validate_create_frequency_modifier(frequency, frequency_modifier) if frequency_modifier
+ validate_create_day(day, frequency, frequency_modifier) if day
validate_create_months(months, frequency) if months
+ validate_frequency_monthly(frequency_modifier, months, day) if frequency == :monthly
validate_idle_time(idle_time, frequency)
+ idempotency_warning_for_frequency_weekly(day, start_day) if frequency == :weekly
end
private
+ ## Resource is not idempotent when day, start_day is not provided with frequency :weekly
+ ## 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 ..
+ ## 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
+ def idempotency_warning_for_frequency_weekly(day, start_day)
+ if start_day.nil? && day.nil?
+ logger.warn "To maintain idempotency for frequency :weekly provide start_day, start_time and day."
+ end
+ end
+
# Validate the passed value is numeric values only if it is a string
def numeric_value_in_string?(val)
return true if Integer(val)
@@ -94,9 +117,35 @@ class Chef
false
end
+ def validate_frequency(frequency)
+ if frequency.nil? || !([:minute, :hourly, :daily, :weekly, :monthly, :once, :on_logon, :onstart, :on_idle, :none].include?(frequency))
+ raise ArgumentError, "Frequency needs to be provided. Valid frequencies are :minute, :hourly, :daily, :weekly, :monthly, :once, :on_logon, :onstart, :on_idle, :none."
+ end
+ end
+
+ def validate_frequency_monthly(frequency_modifier, months, day)
+ # validates the frequency :monthly and raises error if frequency_modifier is first, second, thrid etc and day is not provided
+ if (frequency_modifier != 1) && (frequency_modifier_includes_days_of_weeks?(frequency_modifier)) && !(day)
+ raise ArgumentError, "Please select day on which you want to run the task e.g. 'Mon, Tue'. Multiple values must be seprated by comma."
+ end
+
+ # 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.
+ # 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
+ if (frequency_modifier.to_i.between?(2, 12)) && !(months.nil?)
+ raise ArgumentError, "For frequency :monthly either use property months or frequency_modifier to set months."
+ end
+ end
+
+ # returns true if frequency_modifer has values First, second, third, fourth, last, lastday
+ def frequency_modifier_includes_days_of_weeks?(frequency_modifier)
+ frequency_modifier = frequency_modifier.to_s.split(",")
+ frequency_modifier.map! { |value| value.strip.upcase }
+ (frequency_modifier - VALID_WEEKS).empty?
+ end
+
def validate_random_delay(random_delay, frequency)
- if [:once, :on_logon, :onstart, :on_idle, :none].include? frequency
- raise ArgumentError, "`random_delay` property is supported only for frequency :minute, :hourly, :daily, :weekly and :monthly"
+ if [:on_logon, :onstart, :on_idle, :none].include? frequency
+ raise ArgumentError, "`random_delay` property is supported only for frequency :once, :minute, :hourly, :daily, :weekly and :monthly"
end
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)
@@ -104,12 +153,14 @@ class Chef
# @todo when we drop ruby 2.3 support this should be converted to .match?() instead of =~f
def validate_start_day(start_day, frequency)
- if [:once, :on_logon, :onstart, :on_idle, :none].include? frequency
+ if start_day && frequency == :none
raise ArgumentError, "`start_day` property is not supported with frequency: #{frequency}"
end
# make sure the start_day is in MM/DD/YYYY format: http://rubular.com/r/cgjHemtWl5
- 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
+ if start_day
+ 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
+ end
end
# @todo when we drop ruby 2.3 support this should be converted to .match?() instead of =~
@@ -122,8 +173,6 @@ class Chef
end
end
- SYSTEM_USERS = ['NT AUTHORITY\SYSTEM', "SYSTEM", 'NT AUTHORITY\LOCALSERVICE', 'NT AUTHORITY\NETWORKSERVICE', 'BUILTIN\USERS', "USERS"].freeze
-
def validate_user_and_password(user, password)
if password_required?(user) && password.nil?
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'}
@@ -136,65 +185,79 @@ class Chef
end
def validate_interactive_setting(interactive_enabled, password)
- if interactive_enabled && password.nil?
- raise ArgumentError, "Please provide the password when attempting to set interactive/non-interactive."
- end
+ raise ArgumentError, "Please provide the password when attempting to set interactive/non-interactive." if interactive_enabled && password.nil?
end
def validate_create_frequency_modifier(frequency, frequency_modifier)
- # Currently is handled in create action 'frequency_modifier_allowed' line. Does not allow for frequency_modifier for once,onstart,onlogon,onidle,none
- # Note that 'OnEvent' is not a supported frequency.
- unless frequency.nil? || frequency_modifier.nil?
- case frequency
- when :minute
- unless frequency_modifier.to_i > 0 && frequency_modifier.to_i <= 1439
- raise ArgumentError, "frequency_modifier value #{frequency_modifier} is invalid. Valid values for :minute frequency are 1 - 1439."
- end
- when :hourly
- unless frequency_modifier.to_i > 0 && frequency_modifier.to_i <= 23
- raise ArgumentError, "frequency_modifier value #{frequency_modifier} is invalid. Valid values for :hourly frequency are 1 - 23."
- end
- when :daily
- unless frequency_modifier.to_i > 0 && frequency_modifier.to_i <= 365
- raise ArgumentError, "frequency_modifier value #{frequency_modifier} is invalid. Valid values for :daily frequency are 1 - 365."
- end
- when :weekly
- unless frequency_modifier.to_i > 0 && frequency_modifier.to_i <= 52
- raise ArgumentError, "frequency_modifier value #{frequency_modifier} is invalid. Valid values for :weekly frequency are 1 - 52."
- end
- when :monthly
- unless ("1".."12").to_a.push("FIRST", "SECOND", "THIRD", "FOURTH", "LAST", "LASTDAY").include?(frequency_modifier.to_s.upcase)
- raise ArgumentError, "frequency_modifier value #{frequency_modifier} is invalid. Valid values for :monthly frequency are 1 - 12, 'FIRST', 'SECOND', 'THIRD', 'FOURTH', 'LAST', 'LASTDAY'."
+ if ([:on_logon, :onstart, :on_idle, :none].include?(frequency)) && ( frequency_modifier != 1)
+ raise ArgumentError, "frequency_modifier property not supported with frequency :#{frequency}"
+ end
+
+ if frequency == :monthly
+ unless (1..12).cover?(frequency_modifier.to_i) || frequency_modifier_includes_days_of_weeks?(frequency_modifier)
+ raise ArgumentError, "frequency_modifier value #{frequency_modifier} is invalid. Valid values for :monthly frequency are 1 - 12, 'FIRST', 'SECOND', 'THIRD', 'FOURTH', 'LAST'."
+ end
+ else
+ unless frequency.nil? || frequency_modifier.nil?
+ frequency_modifier = frequency_modifier.to_i
+ min = 1
+ max = case frequency
+ when :minute
+ 1439
+ when :hourly
+ 23
+ when :daily
+ 365
+ when :weekly
+ 52
+ else
+ min
+ end
+ unless frequency_modifier.between?(min, max)
+ raise ArgumentError, "frequency_modifier value #{frequency_modifier} is invalid. Valid values for :#{frequency} frequency are #{min} - #{max}."
end
end
end
end
- def validate_create_day(day, frequency)
- unless [:weekly, :monthly].include?(frequency)
- raise "day property is only valid for tasks that run monthly or weekly"
- end
+ def validate_create_day(day, frequency, frequency_modifier)
+ raise ArgumentError, "day property is only valid for tasks that run monthly or weekly" unless [:weekly, :monthly].include?(frequency)
+
+ # This has been verified with schtask.exe https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/schtasks#d-dayday--
+ # verified with earlier code if day "*" is given with frequency it raised exception Invalid value for /D option
+ raise ArgumentError, "day wild card (*) is only valid with frequency :weekly" if frequency == :monthly && day == "*"
+
if day.is_a?(String) && day.to_i.to_s != day
days = day.split(",")
- days.each do |d|
- unless ["mon", "tue", "wed", "thu", "fri", "sat", "sun", "*"].include?(d.strip.downcase)
- raise ArgumentError, "day property invalid. Only valid values are: MON, TUE, WED, THU, FRI, SAT, SUN and *. Multiple values must be separated by a comma."
+ if days_includes_days_of_months?(days)
+ # 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
+ raise ArgumentError, "day values 1-31 or last is only valid with frequency :monthly" if frequency == :weekly
+ else
+ days.map! { |day| day.to_s.strip.downcase }
+ unless (days - VALID_WEEK_DAYS).empty?
+ raise ArgumentError, "day property invalid. Only valid values are: #{VALID_WEEK_DAYS.map(&:upcase).join(', ')}. Multiple values must be separated by a comma."
end
end
end
end
def validate_create_months(months, frequency)
- raise ArgumentError, "months property is only valid for tasks that run monthly" unless frequency == :monthly
- if months.is_a? String
- months.split(",").each do |month|
- unless ["JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC", "*"].include?(month.strip.upcase)
- raise ArgumentError, "months property invalid. Only valid values are: JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC and *. Multiple values must be separated by a comma."
- end
+ raise ArgumentError, "months property is only valid for tasks that run monthly" if frequency != :monthly
+ if months.is_a?(String)
+ months = months.split(",")
+ months.map! { |month| month.strip.upcase }
+ unless (months - VALID_MONTHS).empty?
+ raise ArgumentError, "months property invalid. Only valid values are: #{VALID_MONTHS.join(', ')}. Multiple values must be separated by a comma."
end
end
end
+ # This method returns true if day has values from 1-31 which is a days of moths and used with frequency :monthly
+ def days_includes_days_of_months?(days)
+ days.map! { |day| day.to_s.strip.downcase }
+ (days - VALID_DAYS_OF_MONTH).empty?
+ end
+
def validate_idle_time(idle_time, frequency)
if !idle_time.nil? && frequency != :on_idle
raise ArgumentError, "idle_time property is only valid for tasks that run on_idle"
@@ -216,6 +279,9 @@ class Chef
ISO8601::Duration.new(seconds.to_i).to_s
end
+ def sec_to_min(seconds)
+ seconds.to_i / 60
+ end
end
end
end