Skip to content

Commit

Permalink
Merge pull request chef#941 from opscode/adamed-OC-8622-aix-cron
Browse files Browse the repository at this point in the history
OC-8622: Add support for the cron resource for AIX
  • Loading branch information
Adam Edwards committed Aug 6, 2013
2 parents ca583b3 + 638f17f commit 62148fe
Show file tree
Hide file tree
Showing 10 changed files with 342 additions and 62 deletions.
17 changes: 13 additions & 4 deletions lib/chef/mixin/command.rb
Expand Up @@ -56,8 +56,17 @@ module Command
# === Returns
# Returns the exit status of args[:command]
def run_command(args={})
command_output = ""
status, stdout, stderr = run_command_and_return_stdout_stderr(args)

status
end

# works same as above, except that it returns stdout and stderr
# requirement => platforms like solaris 9,10 has wierd issues where
# even in command failure the exit code is zero, so we need to lookup stderr.
def run_command_and_return_stdout_stderr(args={})
command_output = ""

args[:ignore_failure] ||= false
args[:output_on_failure] ||= false

Expand All @@ -73,10 +82,10 @@ def run_command(args={})
command_output << "STDOUT: #{stdout}"
command_output << "STDERR: #{stderr}"
handle_command_failures(status, command_output, args)
status

return status, stdout, stderr
end

def output_of_command(command, args)
Chef::Log.debug("Executing #{command}")
stderr_string, stdout_string, status = "", "", nil
Expand Down
3 changes: 2 additions & 1 deletion lib/chef/platform/provider_mapping.rb
Expand Up @@ -322,7 +322,8 @@ def platforms
:default => {
:group => Chef::Provider::Group::Aix,
:mount => Chef::Provider::Mount::Aix,
:ifconfig => Chef::Provider::Ifconfig::Aix
:ifconfig => Chef::Provider::Ifconfig::Aix,
:cron => Chef::Provider::Cron::Aix
}
},
:default => {
Expand Down
34 changes: 24 additions & 10 deletions lib/chef/provider/cron.rb
Expand Up @@ -45,6 +45,7 @@ def load_current_resource
crontab_lines = []
@current_resource = Chef::Resource::Cron.new(@new_resource.name)
@current_resource.user(@new_resource.user)
@cron_exists = false
if crontab = read_crontab
cron_found = false
crontab.each_line do |line|
Expand Down Expand Up @@ -93,14 +94,7 @@ def action_create
newcron = String.new
cron_found = false

newcron << "# Chef Name: #{new_resource.name}\n"
[ :mailto, :path, :shell, :home ].each do |v|
newcron << "#{v.to_s.upcase}=#{@new_resource.send(v)}\n" if @new_resource.send(v)
end
@new_resource.environment.each do |name, value|
newcron << "#{name}=#{value}\n"
end
newcron << "#{@new_resource.minute} #{@new_resource.hour} #{@new_resource.day} #{@new_resource.month} #{@new_resource.weekday} #{@new_resource.command}\n"
newcron = get_crontab_entry

if @cron_exists
unless cron_different?
Expand Down Expand Up @@ -202,13 +196,33 @@ def read_crontab
end

def write_crontab(crontab)
write_exception = false
status = popen4("crontab -u #{@new_resource.user} -", :waitlast => true) do |pid, stdin, stdout, stderr|
stdin.write crontab
begin
stdin.write crontab
rescue Errno::EPIPE => e
# popen4 could yield while child has already died.
write_exception = true
Chef::Log.debug("#{e.message}")
end
end
if status.exitstatus > 0
if status.exitstatus > 0 || write_exception
raise Chef::Exceptions::Cron, "Error updating state of #{@new_resource.name}, exit: #{status.exitstatus}"
end
end

def get_crontab_entry
newcron = ""
newcron << "# Chef Name: #{new_resource.name}\n"
[ :mailto, :path, :shell, :home ].each do |v|
newcron << "#{v.to_s.upcase}=#{@new_resource.send(v)}\n" if @new_resource.send(v)
end
@new_resource.environment.each do |name, value|
newcron << "#{name}=#{value}\n"
end
newcron << "#{@new_resource.minute} #{@new_resource.hour} #{@new_resource.day} #{@new_resource.month} #{@new_resource.weekday} #{@new_resource.command}\n"
newcron
end
end
end
end
48 changes: 48 additions & 0 deletions lib/chef/provider/cron/aix.rb
@@ -0,0 +1,48 @@
#
# Author:: Kaustubh Deorukhkar (<kaustubh@clogeny.com>)
# Copyright:: Copyright (c) 2013 Opscode, Inc.
# License:: Apache License, Version 2.0
#
# 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.
#

require "chef/provider/cron/unix"

class Chef
class Provider
class Cron
class Aix < Chef::Provider::Cron::Unix

private

# For AIX we ignore env vars/[ :mailto, :path, :shell, :home ]
def get_crontab_entry
if env_vars_are_set?
raise Chef::Exceptions::Cron, "Aix cron entry does not support environment variables. Please set them in script and use script in cron."
end

newcron = ""
newcron << "# Chef Name: #{new_resource.name}\n"
newcron << "#{@new_resource.minute} #{@new_resource.hour} #{@new_resource.day} #{@new_resource.month} #{@new_resource.weekday}"

newcron << " #{@new_resource.command}\n"
newcron
end

def env_vars_are_set?
@new_resource.environment.length > 0 || !@new_resource.mailto.nil? || !@new_resource.path.nil? || !@new_resource.shell.nil? || !@new_resource.home.nil?
end
end
end
end
end
46 changes: 6 additions & 40 deletions lib/chef/provider/cron/solaris.rb
@@ -1,15 +1,13 @@
#
# Author:: Bryan McLellan (btm@loftninjas.org)
# Author:: Toomas Pelberg (toomasp@gmx.net)
# Copyright:: Copyright (c) 2009 Bryan McLellan
# Copyright:: Copyright (c) 2010 Toomas Pelberg
# Author:: Kaustubh Deorukhkar (<kaustubh@clogeny.com>)
# Copyright:: Copyright (c) 2013 Opscode, Inc.
# License:: Apache License, Version 2.0
#
# 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
# 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,
Expand All @@ -18,39 +16,7 @@
# limitations under the License.
#

require 'chef/log'
require 'chef/provider'
require "chef/provider/cron/unix"

class Chef
class Provider
class Cron
class Solaris < Chef::Provider::Cron

private

def read_crontab
crontab = nil
status = popen4("crontab -l #{@new_resource.user}") do |pid, stdin, stdout, stderr|
crontab = stdout.read
end
if status.exitstatus > 1
raise Chef::Exceptions::Cron, "Error determining state of #{@new_resource.name}, exit: #{status.exitstatus}"
end
crontab
end

def write_crontab(crontab)
tempcron = Tempfile.new("chef-cron")
tempcron << crontab
tempcron.flush
tempcron.chmod(0644)
status = run_command(:command => "/usr/bin/crontab #{tempcron.path}",:user => @new_resource.user)
tempcron.close!
if status.exitstatus > 0
raise Chef::Exceptions::Cron, "Error updating state of #{@new_resource.name}, exit: #{status.exitstatus}"
end
end
end
end
end
end
# Just to create an alias so 'Chef::Provider::Cron::Solaris' is exposed and accessible to existing consumers of class.
Chef::Provider::Cron::Solaris = Chef::Provider::Cron::Unix
76 changes: 76 additions & 0 deletions lib/chef/provider/cron/unix.rb
@@ -0,0 +1,76 @@
#
# Author:: Bryan McLellan (btm@loftninjas.org)
# Author:: Toomas Pelberg (toomasp@gmx.net)
# Copyright:: Copyright (c) 2009 Bryan McLellan
# Copyright:: Copyright (c) 2010 Toomas Pelberg
# License:: Apache License, Version 2.0
#
# 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.
#

require 'chef/log'
require 'chef/provider'

class Chef
class Provider
class Cron
class Unix < Chef::Provider::Cron

private

def read_crontab
crontab = nil
status = popen4("crontab -l #{@new_resource.user}") do |pid, stdin, stdout, stderr|
crontab = stdout.read
end
if status.exitstatus > 1
raise Chef::Exceptions::Cron, "Error determining state of #{@new_resource.name}, exit: #{status.exitstatus}"
end
crontab
end

def write_crontab(crontab)
tempcron = Tempfile.new("chef-cron")
tempcron << crontab
tempcron.flush
tempcron.chmod(0644)
exit_status = 0
error_message = ""
begin
status, stdout, stderr = run_command_and_return_stdout_stderr(:command => "/usr/bin/crontab #{tempcron.path}",:user => @new_resource.user)
exit_status = status.exitstatus
# solaris9, 10 on some failures for example invalid 'mins' in crontab fails with exit code of zero :(
if stderr && stderr.include?("errors detected in input, no crontab file generated")
error_message = stderr
exit_status = 1
end
rescue Chef::Exceptions::Exec => e
Chef::Log.debug(e.message)
exit_status = 1
error_message = e.message
rescue ArgumentError => e
# usually raised on invalid user.
Chef::Log.debug(e.message)
exit_status = 1
error_message = e.message
end
tempcron.close!
if exit_status > 0
raise Chef::Exceptions::Cron, "Error updating state of #{@new_resource.name}, exit: #{exit_status}, message: #{error_message}"
end
end

end
end
end
end
1 change: 1 addition & 0 deletions lib/chef/providers.rb
Expand Up @@ -21,6 +21,7 @@
require 'chef/provider/cookbook_file'
require 'chef/provider/cron'
require 'chef/provider/cron/solaris'
require 'chef/provider/cron/aix'
require 'chef/provider/deploy'
require 'chef/provider/directory'
require 'chef/provider/env'
Expand Down

0 comments on commit 62148fe

Please sign in to comment.