class Chef::Provider::Cron

Constants

CRON_ATTRIBUTES
CRON_PATTERN
ENV_PATTERN
SPECIAL_PATTERN
SPECIAL_TIME_VALUES
Solaris

Just to create an alias so 'Chef::Provider::Cron::Solaris' is exposed and accessible to existing consumers of class.

WEEKDAY_SYMBOLS

Attributes

cron_empty[RW]
cron_exists[RW]

Public Class Methods

new(new_resource, run_context) click to toggle source
Calls superclass method Chef::Provider.new
# File lib/chef/provider/cron.rb, line 36
def initialize(new_resource, run_context)
  super(new_resource, run_context)
  @cron_exists = false
  @cron_empty = false
end

Public Instance Methods

action_create() click to toggle source
# File lib/chef/provider/cron.rb, line 101
def action_create
  crontab = String.new
  newcron = String.new
  cron_found = false

  newcron = get_crontab_entry

  if @cron_exists
    unless cron_different?
      Chef::Log.debug("Skipping existing cron entry '#{@new_resource.name}'")
      return
    end
    read_crontab.each_line do |line|
      case line.chomp
      when "# Chef Name: #{@new_resource.name}"
        cron_found = true
        next
      when ENV_PATTERN
        crontab << line unless cron_found
        next
      when CRON_PATTERN
        if cron_found
          cron_found = false
          crontab << newcron
          next
        end
      else
        if cron_found # We've got a Chef comment with no following crontab line
          crontab << newcron
          cron_found = false
        end
      end
      crontab << line
    end

    # Handle edge case where the Chef comment is the last line in the current crontab
    crontab << newcron if cron_found

    converge_by("update crontab entry for #{@new_resource}") do
      write_crontab crontab
      Chef::Log.info("#{@new_resource} updated crontab entry")
    end

  else
    crontab = read_crontab unless @cron_empty
    crontab << newcron

    converge_by("add crontab entry for #{@new_resource}") do
      write_crontab crontab
      Chef::Log.info("#{@new_resource} added crontab entry")
    end
  end
end
action_delete() click to toggle source
# File lib/chef/provider/cron.rb, line 155
def action_delete
  if @cron_exists
    crontab = String.new
    cron_found = false
    read_crontab.each_line do |line|
      case line.chomp
      when "# Chef Name: #{@new_resource.name}"
        cron_found = true
        next
      when ENV_PATTERN
        next if cron_found
      when CRON_PATTERN
        if cron_found
          cron_found = false
          next
        end
      else
        # We've got a Chef comment with no following crontab line
        cron_found = false
      end
      crontab << line
    end
    description = cron_found ? "remove #{@new_resource.name} from crontab" :
      "save unmodified crontab"
    converge_by(description) do
      write_crontab crontab
      Chef::Log.info("#{@new_resource} deleted crontab entry")
    end
  end
end
cron_different?() click to toggle source
# File lib/chef/provider/cron.rb, line 95
def cron_different?
  CRON_ATTRIBUTES.any? do |cron_var|
    @new_resource.send(cron_var) != @current_resource.send(cron_var)
  end
end
load_current_resource() click to toggle source
# File lib/chef/provider/cron.rb, line 47
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|
      case line.chomp
      when "# Chef Name: #{@new_resource.name}"
        Chef::Log.debug("Found cron '#{@new_resource.name}'")
        cron_found = true
        @cron_exists = true
        next
      when ENV_PATTERN
        set_environment_var($1, $2) if cron_found
        next
      when SPECIAL_PATTERN
        if cron_found
          @current_resource.time($2.to_sym)
          @current_resource.command($3)
          cron_found=false
        end
      when CRON_PATTERN
        if cron_found
          @current_resource.minute($1)
          @current_resource.hour($2)
          @current_resource.day($3)
          @current_resource.month($4)
          @current_resource.weekday($5)
          @current_resource.command($6)
          cron_found=false
        end
        next
      else
        cron_found=false # We've got a Chef comment with no following crontab line
        next
      end
    end
    Chef::Log.debug("Cron '#{@new_resource.name}' not found") unless @cron_exists
  else
    Chef::Log.debug("Cron empty for '#{@new_resource.user}'")
    @cron_empty = true
  end

  @current_resource
end
whyrun_supported?() click to toggle source
# File lib/chef/provider/cron.rb, line 43
def whyrun_supported?
  true
end

Private Instance Methods

get_crontab_entry() click to toggle source
# File lib/chef/provider/cron.rb, line 223
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
  if @new_resource.time
    newcron << "@#{@new_resource.time} #{@new_resource.command}\n"
  else
    newcron << "#{@new_resource.minute} #{@new_resource.hour} #{@new_resource.day} #{@new_resource.month} #{@new_resource.weekday} #{@new_resource.command}\n"
  end
  newcron
end
read_crontab() click to toggle source
# File lib/chef/provider/cron.rb, line 196
def read_crontab
  crontab = nil
  status = popen4("crontab -l -u #{@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
set_environment_var(attr_name, attr_value) click to toggle source
# File lib/chef/provider/cron.rb, line 188
def set_environment_var(attr_name, attr_value)
  if %w(MAILTO PATH SHELL HOME).include?(attr_name)
    @current_resource.send(attr_name.downcase.to_sym, attr_value)
  else
    @current_resource.environment(@current_resource.environment.merge(attr_name => attr_value))
  end
end
weekday_in_crontab() click to toggle source
# File lib/chef/provider/cron.rb, line 240
def weekday_in_crontab
  weekday_in_crontab = WEEKDAY_SYMBOLS.index(@new_resource.weekday)
  if weekday_in_crontab.nil?
    @new_resource.weekday
  else
    weekday_in_crontab.to_s
  end
end
write_crontab(crontab) click to toggle source
# File lib/chef/provider/cron.rb, line 207
def write_crontab(crontab)
  write_exception = false
  status = popen4("crontab -u #{@new_resource.user} -", :waitlast => true) do |pid, stdin, stdout, stderr|
    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 || write_exception
    raise Chef::Exceptions::Cron, "Error updating state of #{@new_resource.name}, exit: #{status.exitstatus}"
  end
end