forked from puppetlabs/puppet
-
Notifications
You must be signed in to change notification settings - Fork 2
/
tagmail.rb
179 lines (152 loc) · 5.71 KB
/
tagmail.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
require 'puppet'
require 'pp'
require 'net/smtp'
require 'time'
Puppet::Reports.register_report(:tagmail) do
desc "This report sends specific log messages to specific email addresses
based on the tags in the log messages.
See the [documentation on tags](http://projects.puppetlabs.com/projects/puppet/wiki/Using_Tags) for more information.
To use this report, you must create a `tagmail.conf` file in the location
specified by the `tagmap` setting. This is a simple file that maps tags to
email addresses: Any log messages in the report that match the specified
tags will be sent to the specified email addresses.
Lines in the `tagmail.conf` file consist of a comma-separated list
of tags, a colon, and a comma-separated list of email addresses.
Tags can be !negated with a leading exclamation mark, which will
subtract any messages with that tag from the set of events handled
by that line.
Puppet's log levels (`debug`, `info`, `notice`, `warning`, `err`,
`alert`, `emerg`, `crit`, and `verbose`) can also be used as tags,
and there is an `all` tag that will always match all log messages.
An example `tagmail.conf`:
all: me@domain.com
webserver, !mailserver: httpadmins@domain.com
This will send all messages to `me@domain.com`, and all messages from
webservers that are not also from mailservers to `httpadmins@domain.com`.
If you are using anti-spam controls such as grey-listing on your mail
server, you should whitelist the sending email address (controlled by
`reportfrom` configuration option) to ensure your email is not discarded as spam.
"
# Find all matching messages.
def match(taglists)
matching_logs = []
taglists.each do |emails, pos, neg|
# First find all of the messages matched by our positive tags
messages = nil
if pos.include?("all")
messages = self.logs
else
# Find all of the messages that are tagged with any of our
# tags.
messages = self.logs.find_all do |log|
pos.detect { |tag| log.tagged?(tag) }
end
end
# Now go through and remove any messages that match our negative tags
messages = messages.reject do |log|
true if neg.detect do |tag| log.tagged?(tag) end
end
if messages.empty?
Puppet.info "No messages to report to #{emails.join(",")}"
next
else
matching_logs << [emails, messages.collect { |m| m.to_report }.join("\n")]
end
end
matching_logs
end
# Load the config file
def parse(text)
taglists = []
text.split("\n").each do |line|
taglist = emails = nil
case line.chomp
when /^\s*#/; next
when /^\s*$/; next
when /^\s*(.+)\s*:\s*(.+)\s*$/
taglist = $1
emails = $2.sub(/#.*$/,'')
else
raise ArgumentError, "Invalid tagmail config file"
end
pos = []
neg = []
taglist.sub(/\s+$/,'').split(/\s*,\s*/).each do |tag|
unless tag =~ /^!?[-\w\.]+$/
raise ArgumentError, "Invalid tag #{tag.inspect}"
end
case tag
when /^\w+/; pos << tag
when /^!\w+/; neg << tag.sub("!", '')
else
raise Puppet::Error, "Invalid tag '#{tag}'"
end
end
# Now split the emails
emails = emails.sub(/\s+$/,'').split(/\s*,\s*/)
taglists << [emails, pos, neg]
end
taglists
end
# Process the report. This just calls the other associated messages.
def process
unless FileTest.exists?(Puppet[:tagmap])
Puppet.notice "Cannot send tagmail report; no tagmap file #{Puppet[:tagmap]}"
return
end
metrics = raw_summary['resources'] || {} rescue {}
if metrics['out_of_sync'] == 0 && metrics['changed'] == 0
Puppet.notice "Not sending tagmail report; no changes"
return
end
taglists = parse(File.read(Puppet[:tagmap]))
# Now find any appropriately tagged messages.
reports = match(taglists)
send(reports) unless reports.empty?
end
# Send the email reports.
def send(reports)
pid = Puppet::Util.safe_posix_fork do
if Puppet[:smtpserver] != "none"
begin
Net::SMTP.start(Puppet[:smtpserver], Puppet[:smtpport], Puppet[:smtphelo]) do |smtp|
reports.each do |emails, messages|
smtp.open_message_stream(Puppet[:reportfrom], *emails) do |p|
p.puts "From: #{Puppet[:reportfrom]}"
p.puts "Subject: Puppet Report for #{self.host}"
p.puts "To: " + emails.join(", ")
p.puts "Date: #{Time.now.rfc2822}"
p.puts
p.puts messages
end
end
end
rescue => detail
message = "Could not send report emails through smtp: #{detail}"
Puppet.log_exception(detail, message)
raise Puppet::Error, message
end
elsif Puppet[:sendmail] != ""
begin
reports.each do |emails, messages|
# We need to open a separate process for every set of email addresses
IO.popen(Puppet[:sendmail] + " " + emails.join(" "), "w") do |p|
p.puts "From: #{Puppet[:reportfrom]}"
p.puts "Subject: Puppet Report for #{self.host}"
p.puts "To: " + emails.join(", ")
p.puts messages
end
end
rescue => detail
message = "Could not send report emails via sendmail: #{detail}"
Puppet.log_exception(detail, message)
raise Puppet::Error, message
end
else
raise Puppet::Error, "SMTP server is unset and could not find sendmail"
end
end
# Don't bother waiting for the pid to return.
Process.detach(pid)
end
end