1
require 'puppet/provider/parsedfile'
3
tab = case Facter.value(:operatingsystem)
4
when "Solaris": :suntab
10
Puppet::Type.type(:cron).provide(:crontab,
11
:parent => Puppet::Provider::ParsedFile,
12
:default_target => ENV["USER"] || "root",
15
commands :crontab => "crontab"
17
text_line :comment, :match => %r{^#}, :post_parse => proc { |record|
18
if record[:line] =~ /Puppet Name: (.+)\s*$/
23
text_line :blank, :match => %r{^\s*$}
25
text_line :environment, :match => %r{^\w+=}
27
record_line :freebsd_special, :fields => %w{special command},
28
:match => %r{^@(\w+)\s+(.+)$}, :pre_gen => proc { |record|
29
record[:special] = "@" + record[:special]
32
crontab = record_line :crontab, :fields => %w{minute hour monthday month weekday command},
33
:match => %r{^\s*(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(.+)$},
34
:optional => %w{minute hour weekday month monthday}, :absent => "*"
40
# Do some post-processing of the parsed record. Basically just
41
# split the numeric fields on ','.
42
def post_parse(record)
43
numeric_fields.each do |field|
44
if val = record[field] and val != :absent
45
record[field] = record[field].split(",")
50
# Join the fields back up based on ','.
52
numeric_fields.each do |field|
53
if vals = record[field] and vals.is_a?(Array)
54
record[field] = vals.join(",")
60
# Add name and environments as necessary.
64
str = "# Puppet Name: %s\n" % record[:name]
66
if record[:environment] and record[:environment] != :absent and record[:environment] != [:absent]
67
record[:environment].each do |env|
73
str += "@%s %s" % [record[:special], record[:command]]
82
# Return the header placed at the top of each generated file, warning
83
# users that modifying this file manually is probably a bad idea.
85
%{# HEADER: This file was autogenerated at #{Time.now} by puppet.
86
# HEADER: While it can still be managed manually, it is definitely not recommended.
87
# HEADER: Note particularly that the comments starting with 'Puppet Name' should
88
# HEADER: not be deleted, as doing so could cause duplicate cron jobs.\n}
91
# See if we can match the record against an existing cron job.
92
def self.match(record, resources)
93
resources.each do |name, resource|
94
# Match the command first, since it's the most important one.
95
next unless record[:target] == resource.value(:target)
96
next unless record[:command] == resource.value(:command)
98
# Then check the @special stuff
100
next unless resource.value(:special) == record[:special]
103
# Then the normal fields.
105
record_type(record[:record_type]).fields().each do |field|
106
next if field == :command
107
next if field == :special
108
if record[field] and ! resource.value(field)
109
#Puppet.info "Cron is missing %s: %s and %s" %
110
# [field, record[field].inspect, resource.value(field).inspect]
115
if ! record[field] and resource.value(field)
116
#Puppet.info "Hash is missing %s: %s and %s" %
117
# [field, resource.value(field).inspect, record[field].inspect]
122
# Yay differing definitions of absent.
123
next if (record[field] == :absent and resource.value(field) == "*")
125
# Everything should be in the form of arrays, not the normal text.
126
next if (record[field] == resource.value(field))
127
#Puppet.info "Did not match %s: %s vs %s" %
128
# [field, resource.value(field).inspect, record[field].inspect]
132
return resource if matched
138
# Collapse name and env records.
139
def self.prefetch_hook(records)
142
result = records.each { |record|
143
case record[:record_type]
149
# Start collecting env values
153
# If we're collecting env values (meaning we're in a named cronjob),
154
# store the line and skip the record.
156
envs << record[:line]
166
if envs.nil? or envs.empty?
167
record[:environment] = :absent
169
# Collect all of the environment lines, and mark the records to be skipped,
170
# since their data is included in our crontab record.
171
record[:environment] = envs
173
# And turn off env collection again
177
}.reject { |record| record[:skip] }
181
def self.to_file(records)
183
# Apparently Freebsd will "helpfully" add a new TZ line to every
184
# single cron line, but not in all cases (e.g., it doesn't do it
185
# on my machine). This is my attempt to fix it so the TZ lines don't
187
if text =~ /(^TZ=.+\n)/
196
@property_hash[:user] = user
197
@property_hash[:target] = user
201
@property_hash[:user] || @property_hash[:target]