~ubuntu-branches/ubuntu/oneiric/puppet/oneiric-security

« back to all changes in this revision

Viewing changes to lib/puppet/provider/cron/crontab.rb

  • Committer: Bazaar Package Importer
  • Author(s): Micah Anderson
  • Date: 2008-07-26 15:43:45 UTC
  • mto: (3.1.1 lenny) (1.3.1 upstream)
  • mto: This revision was merged to the branch mainline in revision 16.
  • Revision ID: james.westby@ubuntu.com-20080726154345-1fmgo76b4l72ulvc
ImportĀ upstreamĀ versionĀ 0.24.5

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
require 'puppet/provider/parsedfile'
 
2
 
 
3
tab = case Facter.value(:operatingsystem)
 
4
    when "Solaris": :suntab
 
5
    else
 
6
        :crontab
 
7
    end
 
8
 
 
9
 
 
10
Puppet::Type.type(:cron).provide(:crontab,
 
11
    :parent => Puppet::Provider::ParsedFile,
 
12
    :default_target => ENV["USER"] || "root",
 
13
    :filetype => tab
 
14
) do
 
15
    commands :crontab => "crontab"
 
16
 
 
17
    text_line :comment, :match => %r{^#}, :post_parse => proc { |record|
 
18
        if record[:line] =~ /Puppet Name: (.+)\s*$/
 
19
            record[:name] = $1
 
20
        end
 
21
    }
 
22
 
 
23
    text_line :blank, :match => %r{^\s*$}
 
24
 
 
25
    text_line :environment, :match => %r{^\w+=}
 
26
 
 
27
    record_line :freebsd_special, :fields => %w{special command},
 
28
        :match => %r{^@(\w+)\s+(.+)$}, :pre_gen => proc { |record|
 
29
            record[:special] = "@" + record[:special]
 
30
        }
 
31
 
 
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 => "*"
 
35
 
 
36
    class << crontab
 
37
        def numeric_fields
 
38
            fields - [:command]
 
39
        end
 
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(",")
 
46
                end
 
47
            end
 
48
        end
 
49
 
 
50
        # Join the fields back up based on ','.
 
51
        def pre_gen(record)
 
52
            numeric_fields.each do |field|
 
53
                if vals = record[field] and vals.is_a?(Array)
 
54
                    record[field] = vals.join(",")
 
55
                end
 
56
            end
 
57
        end
 
58
 
 
59
 
 
60
        # Add name and environments as necessary.
 
61
        def to_line(record)
 
62
            str = ""
 
63
            if record[:name]
 
64
                str = "# Puppet Name: %s\n" % record[:name]
 
65
            end
 
66
            if record[:environment] and record[:environment] != :absent and record[:environment] != [:absent]
 
67
                record[:environment].each do |env|
 
68
                    str += env + "\n"
 
69
                end
 
70
            end
 
71
 
 
72
            if record[:special]
 
73
                str += "@%s %s" % [record[:special], record[:command]]
 
74
            else
 
75
                str += join(record)
 
76
            end
 
77
            str
 
78
        end
 
79
    end
 
80
 
 
81
 
 
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.
 
84
    def self.header
 
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}
 
89
    end
 
90
 
 
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)
 
97
 
 
98
            # Then check the @special stuff
 
99
            if record[:special]
 
100
                next unless resource.value(:special) == record[:special]
 
101
            end
 
102
 
 
103
            # Then the normal fields.
 
104
            matched = true
 
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]
 
111
                    matched = false
 
112
                    break
 
113
                end
 
114
 
 
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]
 
118
                    matched = false
 
119
                    break
 
120
                end
 
121
 
 
122
                # Yay differing definitions of absent.
 
123
                next if (record[field] == :absent and resource.value(field) == "*")
 
124
 
 
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]
 
129
                matched = false 
 
130
                break
 
131
            end
 
132
            return resource if matched
 
133
        end
 
134
 
 
135
        return false
 
136
    end
 
137
 
 
138
    # Collapse name and env records.
 
139
    def self.prefetch_hook(records)
 
140
        name = nil
 
141
        envs = nil
 
142
        result = records.each { |record|
 
143
            case record[:record_type]
 
144
            when :comment:
 
145
                if record[:name]
 
146
                    name = record[:name]
 
147
                    record[:skip] = true
 
148
                    
 
149
                    # Start collecting env values
 
150
                    envs = []
 
151
                end
 
152
            when :environment:
 
153
                # If we're collecting env values (meaning we're in a named cronjob),
 
154
                # store the line and skip the record.
 
155
                if envs
 
156
                    envs << record[:line]
 
157
                    record[:skip] = true
 
158
                end
 
159
            when :blank:
 
160
                # nothing
 
161
            else
 
162
                if name
 
163
                    record[:name] = name
 
164
                    name = nil
 
165
                end
 
166
                if envs.nil? or envs.empty?
 
167
                    record[:environment] = :absent
 
168
                else
 
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
 
172
 
 
173
                    # And turn off env collection again
 
174
                    envs = nil
 
175
                end
 
176
            end
 
177
        }.reject { |record| record[:skip] }
 
178
        result
 
179
    end
 
180
 
 
181
    def self.to_file(records)
 
182
        text = super
 
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
 
186
        # multiply.
 
187
        if text =~ /(^TZ=.+\n)/
 
188
            tz = $1 
 
189
            text.sub!(tz, '')
 
190
            text = tz + text
 
191
        end
 
192
        return text
 
193
    end
 
194
 
 
195
    def user=(user)
 
196
        @property_hash[:user] = user
 
197
        @property_hash[:target] = user
 
198
    end
 
199
 
 
200
    def user
 
201
        @property_hash[:user] || @property_hash[:target]
 
202
    end
 
203
end
 
204