Downgrade mysql cookbook for now
It doesn't play well with our current dev server setup
This commit is contained in:
@@ -1,52 +1,384 @@
|
||||
#
|
||||
# Author:: Paul Mooring (<paul@chef.io>)
|
||||
# Cookbook Name:: windows
|
||||
# Resource:: task
|
||||
#
|
||||
# Copyright:: 2012-2015, Chef Software, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
# Passwords can't be loaded for existing tasks, making :modify both confusing
|
||||
# and not very useful
|
||||
actions :create, :delete, :run, :end, :change, :enable, :disable
|
||||
|
||||
attribute :task_name, kind_of: String, name_attribute: true, regex: [/\A[^\/\:\*\?\<\>\|]+\z/]
|
||||
attribute :command, kind_of: String
|
||||
attribute :cwd, kind_of: String
|
||||
attribute :user, kind_of: String, default: 'SYSTEM'
|
||||
attribute :password, kind_of: String, default: nil
|
||||
attribute :run_level, equal_to: [:highest, :limited], default: :limited
|
||||
attribute :force, kind_of: [TrueClass, FalseClass], default: false
|
||||
attribute :interactive_enabled, kind_of: [TrueClass, FalseClass], default: false
|
||||
attribute :frequency_modifier, kind_of: Integer, default: 1
|
||||
attribute :frequency, equal_to: [:minute,
|
||||
:hourly,
|
||||
:daily,
|
||||
:weekly,
|
||||
:monthly,
|
||||
:once,
|
||||
:on_logon,
|
||||
:onstart,
|
||||
:on_idle], default: :hourly
|
||||
attribute :start_day, kind_of: String, default: nil
|
||||
attribute :start_time, kind_of: String, default: nil
|
||||
attribute :day, kind_of: [String, Integer], default: nil
|
||||
|
||||
attr_accessor :exists, :status, :enabled
|
||||
|
||||
def initialize(name, run_context = nil)
|
||||
super
|
||||
@action = :create
|
||||
end
|
||||
#
|
||||
# Author:: Paul Mooring (<paul@chef.io>)
|
||||
# Cookbook:: windows
|
||||
# Resource:: task
|
||||
#
|
||||
# Copyright:: 2012-2017, Chef Software, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
# Passwords can't be loaded for existing tasks, making :modify both confusing
|
||||
# and not very useful
|
||||
|
||||
require 'chef/mixin/shell_out'
|
||||
require 'rexml/document'
|
||||
|
||||
include Chef::Mixin::ShellOut
|
||||
include Chef::Mixin::PowershellOut
|
||||
|
||||
property :task_name, String, name_property: true, regex: [/\A[^\/\:\*\?\<\>\|]+\z/]
|
||||
property :command, String
|
||||
property :cwd, String
|
||||
property :user, String, default: 'SYSTEM'
|
||||
property :password, String
|
||||
property :run_level, equal_to: [:highest, :limited], default: :limited
|
||||
property :force, [true, false], default: false
|
||||
property :interactive_enabled, [true, false], default: false
|
||||
property :frequency_modifier, [Integer, String], default: 1
|
||||
property :frequency, equal_to: [:minute,
|
||||
:hourly,
|
||||
:daily,
|
||||
:weekly,
|
||||
:monthly,
|
||||
:once,
|
||||
:on_logon,
|
||||
:onstart,
|
||||
:on_idle], default: :hourly
|
||||
property :start_day, String
|
||||
property :start_time, String
|
||||
property :day, [String, Integer]
|
||||
property :months, String
|
||||
property :idle_time, Integer
|
||||
property :exists, [true, false], desired_state: true
|
||||
property :status, Symbol, desired_state: true
|
||||
property :enabled, [true, false], desired_state: true
|
||||
|
||||
def load_task_hash(task_name)
|
||||
Chef::Log.debug 'Looking for existing tasks'
|
||||
|
||||
# we use powershell_out here instead of powershell_out! because a failure implies that the task does not exist
|
||||
task_script = <<-EOH
|
||||
[Console]::OutputEncoding = [Text.UTF8Encoding]::UTF8
|
||||
schtasks /Query /FO LIST /V /TN \"#{task_name}\"
|
||||
EOH
|
||||
output = powershell_out(task_script).stdout.force_encoding('UTF-8')
|
||||
if output.empty?
|
||||
task = false
|
||||
else
|
||||
task = {}
|
||||
|
||||
output.split("\n").map! { |line| line.split(':', 2).map!(&:strip) }.each do |field|
|
||||
if field.is_a?(Array) && field[0].respond_to?(:to_sym)
|
||||
task[field[0].gsub(/\s+/, '').to_sym] = field[1]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
task
|
||||
end
|
||||
|
||||
load_current_value do |desired|
|
||||
pathed_task_name = desired.task_name.start_with?('\\') ? desired.task_name : "\\#{desired.task_name}"
|
||||
|
||||
task_hash = load_task_hash pathed_task_name
|
||||
|
||||
task_name pathed_task_name
|
||||
if task_hash.respond_to?(:[]) && task_hash[:TaskName] == pathed_task_name
|
||||
exists true
|
||||
status :running if task_hash[:Status] == 'Running'
|
||||
enabled task_hash[:ScheduledTaskState] == 'Enabled' ? true : false
|
||||
cwd task_hash[:StartIn] unless task_hash[:StartIn] == 'N/A'
|
||||
command task_hash[:TaskToRun]
|
||||
user task_hash[:RunAsUser]
|
||||
else
|
||||
exists false
|
||||
end
|
||||
end
|
||||
|
||||
action :create do
|
||||
if current_resource.exists && !(task_need_update? || new_resource.force)
|
||||
Chef::Log.info "#{new_resource} task already exists - nothing to do"
|
||||
else
|
||||
converge_by("creating a new scheduled task #{new_resource.task_name}") do
|
||||
validate_user_and_password
|
||||
validate_interactive_setting
|
||||
validate_create_frequency_modifier
|
||||
validate_create_day
|
||||
validate_create_months
|
||||
validate_idle_time
|
||||
|
||||
options = {}
|
||||
options['F'] = '' if new_resource.force || task_need_update?
|
||||
options['SC'] = schedule
|
||||
options['MO'] = new_resource.frequency_modifier if frequency_modifier_allowed
|
||||
options['I'] = new_resource.idle_time unless new_resource.idle_time.nil?
|
||||
options['SD'] = new_resource.start_day unless new_resource.start_day.nil?
|
||||
options['ST'] = new_resource.start_time unless new_resource.start_time.nil?
|
||||
options['TR'] = new_resource.command
|
||||
options['RU'] = new_resource.user
|
||||
options['RP'] = new_resource.password if use_password?
|
||||
options['RL'] = 'HIGHEST' if new_resource.run_level == :highest
|
||||
options['IT'] = '' if new_resource.interactive_enabled
|
||||
options['D'] = new_resource.day if new_resource.day
|
||||
options['M'] = new_resource.months unless new_resource.months.nil?
|
||||
|
||||
run_schtasks 'CREATE', options
|
||||
cwd(new_resource.cwd) if new_resource.cwd
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
action :run do
|
||||
if current_resource.exists
|
||||
if current_resource.status == :running
|
||||
Chef::Log.info "#{new_resource} task is currently running, skipping run"
|
||||
else
|
||||
converge_by("running scheduled task #{new_resource.task_name}") do
|
||||
run_schtasks 'RUN'
|
||||
new_resource.updated_by_last_action true
|
||||
end
|
||||
end
|
||||
else
|
||||
Chef::Log.debug "#{new_resource} task doesn't exists - nothing to do"
|
||||
end
|
||||
end
|
||||
|
||||
action :change do
|
||||
if current_resource.exists
|
||||
converge_by("changing scheduled task #{new_resource.task_name}") do
|
||||
validate_user_and_password
|
||||
validate_interactive_setting
|
||||
|
||||
options = {}
|
||||
options['TR'] = new_resource.command if new_resource.command
|
||||
options['RU'] = new_resource.user if new_resource.user
|
||||
options['RP'] = new_resource.password if new_resource.password
|
||||
options['SD'] = new_resource.start_day unless new_resource.start_day.nil?
|
||||
options['ST'] = new_resource.start_time unless new_resource.start_time.nil?
|
||||
options['IT'] = '' if new_resource.interactive_enabled
|
||||
|
||||
run_schtasks 'CHANGE', options
|
||||
cwd(new_resource.cwd) if new_resource.cwd != current_resource.cwd
|
||||
end
|
||||
else
|
||||
Chef::Log.debug "#{new_resource} task doesn't exists - nothing to do"
|
||||
end
|
||||
end
|
||||
|
||||
action :delete do
|
||||
if current_resource.exists
|
||||
converge_by("deleting scheduled task #{new_resource.task_name}") do
|
||||
# always need to force deletion
|
||||
run_schtasks 'DELETE', 'F' => ''
|
||||
end
|
||||
else
|
||||
Chef::Log.debug "#{new_resource} task doesn't exists - nothing to do"
|
||||
end
|
||||
end
|
||||
|
||||
action :end do
|
||||
if current_resource.exists
|
||||
if current_resource.status != :running
|
||||
Chef::Log.debug "#{new_resource} is not running - nothing to do"
|
||||
else
|
||||
converge_by("stopping scheduled task #{new_resource.task_name}") do
|
||||
run_schtasks 'END'
|
||||
end
|
||||
end
|
||||
else
|
||||
Chef::Log.fatal "#{new_resource} task doesn't exist - nothing to do"
|
||||
raise Errno::ENOENT, "#{new_resource}: task does not exist, cannot end"
|
||||
end
|
||||
end
|
||||
|
||||
action :enable do
|
||||
if current_resource.exists
|
||||
if current_resource.enabled
|
||||
Chef::Log.debug "#{new_resource} already enabled - nothing to do"
|
||||
else
|
||||
converge_by("enabling scheduled task #{new_resource.task_name}") do
|
||||
run_schtasks 'CHANGE', 'ENABLE' => ''
|
||||
end
|
||||
end
|
||||
else
|
||||
Chef::Log.fatal "#{new_resource} task doesn't exist - nothing to do"
|
||||
raise Errno::ENOENT, "#{new_resource}: task does not exist, cannot enable"
|
||||
end
|
||||
end
|
||||
|
||||
action :disable do
|
||||
if current_resource.exists
|
||||
if current_resource.enabled
|
||||
converge_by("disabling scheduled task #{new_resource.task_name}") do
|
||||
run_schtasks 'CHANGE', 'DISABLE' => ''
|
||||
end
|
||||
else
|
||||
Chef::Log.debug "#{new_resource} already disabled - nothing to do"
|
||||
end
|
||||
else
|
||||
Chef::Log.debug "#{new_resource} task doesn't exist - nothing to do"
|
||||
end
|
||||
end
|
||||
|
||||
action_class do
|
||||
# rubocop:disable Style/StringLiteralsInInterpolation
|
||||
def run_schtasks(task_action, options = {})
|
||||
cmd = "schtasks /#{task_action} /TN \"#{new_resource.task_name}\" "
|
||||
options.keys.each do |option|
|
||||
cmd += "/#{option} "
|
||||
cmd += "\"#{options[option].to_s.gsub('"', "\\\"")}\" " unless options[option] == ''
|
||||
end
|
||||
Chef::Log.debug('running: ')
|
||||
Chef::Log.debug(" #{cmd}")
|
||||
shell_out!(cmd, returns: [0])
|
||||
end
|
||||
# rubocop:enable Style/StringLiteralsInInterpolation
|
||||
|
||||
def task_need_update?
|
||||
# gsub needed as schtasks converts single quotes to double quotes on creation
|
||||
current_resource.command != new_resource.command.tr("'", '"') ||
|
||||
current_resource.user != new_resource.user
|
||||
end
|
||||
|
||||
def cwd(folder)
|
||||
Chef::Log.debug 'looking for existing tasks'
|
||||
|
||||
# we use shell_out here instead of shell_out! because a failure implies that the task does not exist
|
||||
xml_cmd = shell_out("schtasks /Query /TN \"#{new_resource.task_name}\" /XML")
|
||||
|
||||
return if xml_cmd.exitstatus != 0
|
||||
|
||||
doc = REXML::Document.new(xml_cmd.stdout)
|
||||
|
||||
Chef::Log.debug 'Removing former CWD if any'
|
||||
doc.root.elements.delete('Actions/Exec/WorkingDirectory')
|
||||
|
||||
unless folder.nil?
|
||||
Chef::Log.debug 'Setting CWD as #folder'
|
||||
cwd_element = REXML::Element.new('WorkingDirectory')
|
||||
cwd_element.add_text(folder)
|
||||
exec_element = doc.root.elements['Actions/Exec']
|
||||
exec_element.add_element(cwd_element)
|
||||
end
|
||||
|
||||
temp_task_file = ::File.join(ENV['TEMP'], 'windows_task.xml')
|
||||
begin
|
||||
::File.open(temp_task_file, 'w:UTF-16LE') do |f|
|
||||
doc.write(f)
|
||||
end
|
||||
|
||||
options = {}
|
||||
options['RU'] = new_resource.user if new_resource.user
|
||||
options['RP'] = new_resource.password if new_resource.password
|
||||
options['IT'] = '' if new_resource.interactive_enabled
|
||||
options['XML'] = temp_task_file
|
||||
|
||||
run_schtasks('DELETE', 'F' => '')
|
||||
run_schtasks('CREATE', options)
|
||||
ensure
|
||||
::File.delete(temp_task_file)
|
||||
end
|
||||
end
|
||||
|
||||
SYSTEM_USERS = ['NT AUTHORITY\SYSTEM', 'SYSTEM', 'NT AUTHORITY\LOCALSERVICE', 'NT AUTHORITY\NETWORKSERVICE'].freeze
|
||||
|
||||
def validate_user_and_password
|
||||
return unless new_resource.user && use_password?
|
||||
return unless new_resource.password.nil?
|
||||
Chef::Log.fatal "#{new_resource.task_name}: Can't specify a non-system user without a password!"
|
||||
end
|
||||
|
||||
def validate_interactive_setting
|
||||
return unless new_resource.interactive_enabled && new_resource.password.nil?
|
||||
Chef::Log.fatal "#{new_resource} did not provide a password when attempting to set interactive/non-interactive."
|
||||
end
|
||||
|
||||
def validate_create_day
|
||||
return unless new_resource.day
|
||||
unless [:weekly, :monthly].include?(new_resource.frequency)
|
||||
raise 'day attribute is only valid for tasks that run weekly or monthly'
|
||||
end
|
||||
return unless new_resource.day.is_a?(String) && new_resource.day.to_i.to_s != new_resource.day
|
||||
days = new_resource.day.split(',')
|
||||
days.each do |day|
|
||||
unless ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun', '*'].include?(day.strip.downcase)
|
||||
raise 'day attribute invalid. Only valid values are: MON, TUE, WED, THU, FRI, SAT, SUN and *. Multiple values must be separated by a comma.'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def validate_create_months
|
||||
return unless new_resource.months
|
||||
unless [:monthly].include?(new_resource.frequency)
|
||||
raise 'months attribute is only valid for tasks that run monthly'
|
||||
end
|
||||
return unless new_resource.months.is_a? String
|
||||
months = new_resource.months.split(',')
|
||||
months.each do |month|
|
||||
unless ['JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC', '*'].include?(month.strip.upcase)
|
||||
raise 'months attribute 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
|
||||
end
|
||||
end
|
||||
|
||||
def validate_idle_time
|
||||
return unless new_resource.frequency == :on_idle
|
||||
return if new_resource.idle_time.to_i > 0 && new_resource.idle_time.to_i <= 999
|
||||
raise "idle_time value #{new_resource.idle_time} is invalid. Valid values for :on_idle frequency are 1 - 999."
|
||||
end
|
||||
|
||||
def validate_create_frequency_modifier
|
||||
# Currently is handled in create action 'frequency_modifier_allowed' line. Does not allow for frequency_modifier for once,onstart,onlogon,onidle
|
||||
# Note that 'OnEvent' is not a supported frequency.
|
||||
return if new_resource.frequency.nil? || new_resource.frequency_modifier.nil?
|
||||
case new_resource.frequency
|
||||
when :minute
|
||||
unless new_resource.frequency_modifier.to_i > 0 && new_resource.frequency_modifier.to_i <= 1439
|
||||
raise "frequency_modifier value #{new_resource.frequency_modifier} is invalid. Valid values for :minute frequency are 1 - 1439."
|
||||
end
|
||||
when :hourly
|
||||
unless new_resource.frequency_modifier.to_i > 0 && new_resource.frequency_modifier.to_i <= 23
|
||||
raise "frequency_modifier value #{new_resource.frequency_modifier} is invalid. Valid values for :hourly frequency are 1 - 23."
|
||||
end
|
||||
when :daily
|
||||
unless new_resource.frequency_modifier.to_i > 0 && new_resource.frequency_modifier.to_i <= 365
|
||||
raise "frequency_modifier value #{new_resource.frequency_modifier} is invalid. Valid values for :daily frequency are 1 - 365."
|
||||
end
|
||||
when :weekly
|
||||
unless new_resource.frequency_modifier.to_i > 0 && new_resource.frequency_modifier.to_i <= 52
|
||||
raise "frequency_modifier value #{new_resource.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?(new_resource.frequency_modifier.to_s.upcase)
|
||||
raise "frequency_modifier value #{new_resource.frequency_modifier} is invalid. Valid values for :monthly frequency are 1 - 12, 'FIRST', 'SECOND', 'THIRD', 'FOURTH', 'LAST', 'LASTDAY'."
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def use_password?
|
||||
@use_password ||= !SYSTEM_USERS.include?(new_resource.user.upcase)
|
||||
end
|
||||
|
||||
def schedule
|
||||
case new_resource.frequency
|
||||
when :on_logon
|
||||
'ONLOGON'
|
||||
when :on_idle
|
||||
'ONIDLE'
|
||||
else
|
||||
new_resource.frequency
|
||||
end
|
||||
end
|
||||
|
||||
def frequency_modifier_allowed
|
||||
case new_resource.frequency
|
||||
when :minute, :hourly, :daily, :weekly
|
||||
true
|
||||
when :monthly
|
||||
new_resource.months.nil? || %w(FIRST SECOND THIRD FOURTH LAST LASTDAY).include?(new_resource.frequency_modifier)
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user