3 # Copyright (c) 2004 The Trustees of Princeton University (Trustees).
5 # Faiyaz Ahmed <faiyaza@cs.princeton.edu>
6 # Stephen Soltesz <soltesz@cs.princeton.edu>
8 # $Id: mailer.py,v 1.10 2007/08/08 13:28:06 soltesz Exp $
11 from monitor import config
17 logger = logging.getLogger("monitor")
22 def reformat_for_rt(text):
23 lines = text.split("\n")
26 spaced_text += " %s\n" %line
30 def _setupRTenvironment():
31 os.environ['PATH'] = config.RT_WEB_TOOLS_PATH + ":" + os.environ['PATH']
32 os.environ['RTSERVER'] = config.RT_WEB_SERVER
33 os.environ['RTUSER'] = config.RT_WEB_USER
34 os.environ['RTPASSWD'] = config.RT_WEB_PASSWORD
35 os.environ['RTDEBUG'] = config.RT_WEB_DEBUG
38 def setTicketStatus(ticket_id, status):
40 if ticket_id == None or ticket_id == "":
43 cmd = "rt edit ticket/%s set status=%s" % (ticket_id, status)
45 (f_in, f_out, f_err) = os.popen3(cmd)
47 l_values = value.split('\n')
48 return "".join(l_values).strip()
50 def getTicketStatus(ticket_id):
52 if ticket_id == None or ticket_id == "":
55 cmd = "rt show -t ticket -f id,subject,status,queue,created,told %s" % (ticket_id)
57 (f_in, f_out, f_err) = os.popen3(cmd)
59 l_values = value.split('\n')
62 if len(line) == 0: continue
63 vals = line.split(':')
65 r_values[key] = ":".join(vals[1:])
66 r_values[key] = r_values[key].strip()
68 r_values['Created'] = calendar.timegm(time.strptime(r_values['Created']))
69 r_values['Told'] = calendar.timegm(time.strptime(r_values['Told']))
72 def setAdminCCViaRT(ticket_id, to):
73 # Set ENV Variables/PATH
75 if ticket_id == None or ticket_id == "":
76 raise Exception("ERROR: ticket_id must be set to some integer value")
78 # This will raise an exception if it is not a valid id.
79 i_ticket_id = int(ticket_id)
81 # create a comma-separated list
83 cmd = "rt edit ticket/%s set admincc='%s'" % (ticket_id, s_to)
85 (f_in, f_out, f_err) = os.popen3(cmd)
87 l_values = value.split()
88 f_in.close() ; f_out.close() ; f_err.close()
89 if len(l_values) > 3 and "updated" in l_values[3]:
94 print "ERROR: RT failed to update AdminCC for ticket %s" % ticket_id
98 def setSubjectViaRT(ticket_id, subject):
99 # Set ENV Variables/PATH
100 _setupRTenvironment()
101 if ticket_id == None or ticket_id == "":
102 raise Exception("ERROR: ticket_id must be set to some integer value")
104 # This will raise an exception if it is not a valid id.
105 i_ticket_id = int(ticket_id)
107 cmd = "rt edit ticket/%s set subject='%s'" % (ticket_id, subject)
109 (f_in, f_out, f_err) = os.popen3(cmd)
111 l_values = value.split()
112 f_in.close() ; f_out.close() ; f_err.close()
113 if len(l_values) > 3 and "updated" in l_values[3]:
117 print "VALUE:", value
118 print "ERROR: RT failed to update subject for ticket %s" % ticket_id
123 def addCommentViaRT(ticket_id, comment):
124 # Set ENV Variables/PATH
125 _setupRTenvironment()
126 if ticket_id == None or ticket_id == "":
127 raise Exception("ERROR: ticket_id must be set to some integer value")
129 # This will raise an exception if it is not a valid id.
130 i_ticket_id = int(ticket_id)
132 cmd = "rt comment -m '%s' ticket/%s" % (comment, i_ticket_id)
134 (f_in, f_out, f_err) = os.popen3(cmd)
136 l_values = value.split()
138 f_in.close() ; f_out.close() ; f_err.close()
139 if len(l_values) > 1 and "recorded" in l_values[1]:
144 f_in.close() ; f_out.close() ; f_err.close()
145 print "ERROR: RT failed to add comment to id %s" % ticket_id
146 print "ERROR: %s" % l_err
150 def closeTicketViaRT(ticket_id, comment):
151 # Set ENV Variables/PATH
152 _setupRTenvironment()
153 if ticket_id == None or ticket_id == "":
154 raise Exception("ERROR: ticket_id must be set to some integer value")
156 # This will raise an exception if it is not a valid id.
157 i_ticket_id = int(ticket_id)
159 # Append comment to RT ticket
160 addCommentViaRT(ticket_id, comment)
163 cmd = "rt edit ticket/%s set status=resolved" % i_ticket_id
165 (f_in, f_out, f_err) = os.popen3(cmd)
170 l_values = value.split()
171 if len(l_values) >= 4 and "updated" in l_values[3]:
175 print "VALUE: ", value
177 print "FAILED to resolve Ticket %s" % ticket_id
178 print "FAILED to resolve Ticket %s" % i_ticket_id
182 def emailViaRT(subject, text, to, ticket_id=None):
183 if ticket_id == None or ticket_id == "" or ticket_id == 0:
185 return emailViaRT_NoTicket(subject, text, to)
188 # Set ENV Variables/PATH
189 _setupRTenvironment()
191 if config.mail and not config.debug:
192 setSubjectViaRT(ticket_id, subject)
193 setAdminCCViaRT(ticket_id, to)
195 cmd = "rt correspond -m - %s" % ticket_id
197 (f_in, f_out, f_err) = os.popen3(cmd)
198 #f_in.write(input[:32000])
199 f_in.write(text[:32000])
204 # TODO: rt doesn't write to stderr on error!!!
206 raise Exception, f_err.read()
209 f_out.close(); del f_out
210 f_err.close(); del f_err
216 def emailViaRT_NoTicket(subject, text, to):
217 """Use RT command line tools to send email.
218 return the generated RT ticket ID number.
222 if config.mail and config.debug:
225 # Set ENV Variables/PATH
226 _setupRTenvironment()
228 # NOTE: AdminCc: (in PLC's RT configuration) gets an email sent.
229 # This is not the case (surprisingly) for Cc:
230 input_text = "Subject: %s\n"
231 input_text += "Requestor: %s\n"% FROM
232 input_text += "id: ticket/new\n"
233 input_text += "Queue: %s\n" % config.RT_QUEUE
235 input_text += "AdminCc: %s\n" % recipient
236 #input_text += "AdminCc: %s\n" % config.cc_email
237 input_text += "Text: %s"
239 # Add a space for each new line to get RT to accept the file.
240 spaced_text = reformat_for_rt(text)
242 if config.mail and not config.debug:
243 cmd = "rt create -i -t ticket"
245 (f_in, f_out, f_err) = os.popen3(cmd)
246 input = input_text % (subject, spaced_text)
247 print "length: %s" % len(input)
248 # NOTE: RT hangs with larger input, probably due to some internal
249 # buffering. So, chop off messages at 32000
250 #f_in.write(input[:32000])
251 f_in.write(input[:32000])
256 # TODO: rt doesn't write to stderr on error!!!
258 raise Exception, f_err.read()
260 print "MAILER: ticket value == %s" % value.split()[2]
261 i_ticket = int(value.split()[2])
262 # clean up the child process.
263 f_in.close(); del f_in
264 f_out.close(); del f_out
265 f_err.close(); del f_err
267 elif config.mail and config.debug:
268 email(subject, spaced_text, to)
275 def email(subject, text, to):
276 """Create a mime-message that will render HTML in popular
277 MUAs, text in better ones"""
282 if (config.mail and config.debug) or (not config.mail and not config.debug and config.bcc):
285 out = cStringIO.StringIO() # output buffer for our message
286 txtin = cStringIO.StringIO(text)
288 writer = MimeWriter.MimeWriter(out)
290 # set up some basic headers... we put subject here
291 # because smtplib.sendmail expects it to be in the
294 writer.addheader("Subject", subject)
295 if to.__class__ == [].__class__ :
296 writer.addheader("To", to[0])
298 for dest in to[1:len(to)]:
301 writer.addheader("Cc", cc)
303 writer.addheader("To", to)
305 if config.bcc and not config.debug:
306 writer.addheader("Bcc", config.email)
308 writer.addheader("Reply-To", FROM)
310 writer.addheader("MIME-Version", "1.0")
312 # start the multipart section of the message
313 # multipart/alternative seems to work better
314 # on some MUAs than multipart/mixed
316 writer.startmultipartbody("alternative")
317 writer.flushheaders()
319 # the plain text section
321 subpart = writer.nextpart()
322 subpart.addheader("Content-Transfer-Encoding", "quoted-printable")
323 pout = subpart.startbody("text/plain", [("charset", 'us-ascii')])
324 mimetools.encode(txtin, pout, 'quoted-printable')
327 # Now that we're done, close our writer and
328 # return the message body
336 # mail and debug, 'to' changed at the beginning'
337 # nomail, but report who I'd send to.
339 for mta in [MTA, 'golf.cs.princeton.edu']:
341 # This is normal operation
346 server = smtplib.SMTP(mta)
347 #server = smtplib.SMTP('golf.cs.princeton.edu')
348 server.sendmail(FROM, to, msg)
349 if config.bcc and not config.debug:
350 server.sendmail(FROM, config.email, msg)
352 except Exception, err:
353 print "Mailer error1: failed using MTA(%s) with: %s" % (mta, err)
355 elif not config.debug and not config.mail and config.bcc:
356 for mta in [MTA, 'golf.cs.princeton.edu']:
358 server = smtplib.SMTP(mta)
359 server.sendmail(FROM, to, msg)
361 except Exception, err:
362 print "Mailer error2: failed using MTA(%s) with: %s" % (mta, err)
364 #print "Would mail %s" %to
365 logger.debug("Would send mail to %s" % to)
367 if __name__=="__main__":
371 #email("[spam] bcc test from golf.cs.princeton.edu",
372 # "It gets to both recipients",
373 # "soltesz@cs.utk.edu")
374 emailViaRT("mail via RT", "Let's see if this succeeds...", [FROM])
375 #email("Re: [PL #21323] TEST 7",
376 # mailtxt.newbootcd_one[1] % {'hostname_list':"hostname list..."},