3 # Copyright (c) 2004 The Trustees of Princeton University (Trustees).
5 # Faiyaz Ahmed <faiyaza@cs.princeton.edu>
7 # $Id: mailer.py,v 1.10 2007/08/08 13:28:06 soltesz Exp $
10 from config import config
18 logger = logging.getLogger("monitor")
21 FROM="monitor@planet-lab.org"
23 def reformat_for_rt(text):
24 lines = text.split("\n")
27 spaced_text += " %s\n" %line
31 def _setupRTenvironment():
32 os.environ['PATH'] = os.environ['PATH'] + ":" + monitorconfig.RT_WEB_TOOLS_PATH
33 os.environ['RTSERVER'] = monitorconfig.RT_WEB_SERVER
34 os.environ['RTUSER'] = monitorconfig.RT_WEB_USER
35 os.environ['RTPASSWD'] = monitorconfig.RT_WEB_PASSWORD
36 os.environ['RTDEBUG'] = monitorconfig.RT_WEB_DEBUG
39 def setTicketStatus(ticket_id, status):
41 if ticket_id == None or ticket_id == "":
44 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 %s" % (ticket_id)
56 (f_in, f_out, f_err) = os.popen3(cmd)
58 l_values = value.split('\n')
61 if len(line) == 0: continue
62 vals = line.split(':')
64 r_values[key] = ":".join(vals[1:])
65 r_values[key] = r_values[key].strip()
67 r_values['Created'] = calendar.timegm(time.strptime(r_values['Created']))
70 def setAdminCCViaRT(ticket_id, to):
71 # Set ENV Variables/PATH
73 if ticket_id == None or ticket_id == "":
74 raise Exception("ERROR: ticket_id must be set to some integer value")
76 # This will raise an exception if it is not a valid id.
77 i_ticket_id = int(ticket_id)
79 # create a comma-separated list
81 cmd = "rt edit ticket/%s set admincc='%s'" % (ticket_id, s_to)
82 (f_in, f_out, f_err) = os.popen3(cmd)
84 l_values = value.split()
85 f_in.close() ; f_out.close() ; f_err.close()
86 if len(l_values) > 3 and "updated" in l_values[3]:
91 print "ERROR: RT failed to update AdminCC for ticket %s" % ticket_id
95 def setSubjectViaRT(ticket_id, subject):
96 # Set ENV Variables/PATH
98 if ticket_id == None or ticket_id == "":
99 raise Exception("ERROR: ticket_id must be set to some integer value")
101 # This will raise an exception if it is not a valid id.
102 i_ticket_id = int(ticket_id)
104 cmd = "rt edit ticket/%s set subject='%s'" % (ticket_id, subject)
105 (f_in, f_out, f_err) = os.popen3(cmd)
107 l_values = value.split()
108 f_in.close() ; f_out.close() ; f_err.close()
109 if len(l_values) > 3 and "updated" in l_values[3]:
113 print "VALUE:", value
114 print "ERROR: RT failed to update subject for ticket %s" % ticket_id
119 def addCommentViaRT(ticket_id, comment):
120 # Set ENV Variables/PATH
121 _setupRTenvironment()
122 if ticket_id == None or ticket_id == "":
123 raise Exception("ERROR: ticket_id must be set to some integer value")
125 # This will raise an exception if it is not a valid id.
126 i_ticket_id = int(ticket_id)
128 cmd = "rt comment -m '%s' ticket/%s" % (comment, i_ticket_id)
129 (f_in, f_out, f_err) = os.popen3(cmd)
131 l_values = value.split()
132 f_in.close() ; f_out.close() ; f_err.close()
133 if len(l_values) > 1 and "recorded" in l_values[1]:
138 f_in.close() ; f_out.close() ; f_err.close()
139 print "ERROR: RT failed to add comment to id %s" % ticket_id
143 def closeTicketViaRT(ticket_id, comment):
144 # Set ENV Variables/PATH
145 _setupRTenvironment()
146 if ticket_id == None or ticket_id == "":
147 raise Exception("ERROR: ticket_id must be set to some integer value")
149 # This will raise an exception if it is not a valid id.
150 i_ticket_id = int(ticket_id)
152 # Append comment to RT ticket
153 addCommentViaRT(ticket_id, comment)
156 cmd = "rt edit ticket/%s set status=resolved" % i_ticket_id
157 (f_in, f_out, f_err) = os.popen3(cmd)
162 l_values = value.split()
163 if len(l_values) >= 4 and "updated" in l_values[3]:
167 print "VALUE: ", value
169 print "FAILED to resolve Ticket %s" % ticket_id
170 print "FAILED to resolve Ticket %s" % i_ticket_id
174 def emailViaRT(subject, text, to, ticket_id=None):
175 if ticket_id == None or ticket_id == "":
177 return emailViaRT_NoTicket(subject, text, to)
180 # Set ENV Variables/PATH
181 _setupRTenvironment()
183 if config.mail and not config.debug:
184 setSubjectViaRT(ticket_id, subject)
185 setAdminCCViaRT(ticket_id, to)
187 cmd = "rt correspond -m - %s" % ticket_id
188 (f_in, f_out, f_err) = os.popen3(cmd)
194 # TODO: rt doesn't write to stderr on error!!!
196 raise Exception, f_err.read()
199 f_out.close(); del f_out
200 f_err.close(); del f_err
206 def emailViaRT_NoTicket(subject, text, to):
207 """Use RT command line tools to send email.
208 return the generated RT ticket ID number.
212 if config.mail and config.debug:
215 # Set ENV Variables/PATH
216 _setupRTenvironment()
218 # NOTE: AdminCc: (in PLC's RT configuration) gets an email sent.
219 # This is not the case (surprisingly) for Cc:
220 input_text = "Subject: %s\n"
221 input_text += "Requestor: monitor@planet-lab.org\n"
222 input_text += "id: ticket/new\n"
223 input_text += "Queue: Monitor\n"
225 input_text += "AdminCc: %s\n" % recipient
226 input_text += "Text: %s"
228 # Add a space for each new line to get RT to accept the file.
229 spaced_text = reformat_for_rt(text)
231 if config.mail and not config.debug:
232 cmd = "rt create -i -t ticket"
233 (f_in, f_out, f_err) = os.popen3(cmd)
234 f_in.write(input_text % (subject, spaced_text))
239 # TODO: rt doesn't write to stderr on error!!!
241 raise Exception, f_err.read()
243 print "MAILER: ticket value == %s" % value.split()[2]
244 i_ticket = int(value.split()[2])
245 # clean up the child process.
246 f_in.close(); del f_in
247 f_out.close(); del f_out
248 f_err.close(); del f_err
250 elif config.mail and config.debug:
251 email(subject, spaced_text, to)
258 def email(subject, text, to):
259 """Create a mime-message that will render HTML in popular
260 MUAs, text in better ones"""
265 if (config.mail and config.debug) or (not config.mail and not config.debug and config.bcc):
268 out = cStringIO.StringIO() # output buffer for our message
269 txtin = cStringIO.StringIO(text)
271 writer = MimeWriter.MimeWriter(out)
273 # set up some basic headers... we put subject here
274 # because smtplib.sendmail expects it to be in the
277 writer.addheader("Subject", subject)
278 if to.__class__ == [].__class__ :
279 writer.addheader("To", to[0])
281 for dest in to[1:len(to)]:
284 writer.addheader("Cc", cc)
286 writer.addheader("To", to)
288 if config.bcc and not config.debug:
289 writer.addheader("Bcc", config.email)
291 writer.addheader("Reply-To", 'monitor@planet-lab.org')
293 writer.addheader("MIME-Version", "1.0")
295 # start the multipart section of the message
296 # multipart/alternative seems to work better
297 # on some MUAs than multipart/mixed
299 writer.startmultipartbody("alternative")
300 writer.flushheaders()
302 # the plain text section
304 subpart = writer.nextpart()
305 subpart.addheader("Content-Transfer-Encoding", "quoted-printable")
306 pout = subpart.startbody("text/plain", [("charset", 'us-ascii')])
307 mimetools.encode(txtin, pout, 'quoted-printable')
310 # Now that we're done, close our writer and
311 # return the message body
319 # mail and debug, 'to' changed at the beginning'
320 # nomail, but report who I'd send to.
322 for mta in [MTA, 'golf.cs.princeton.edu']:
324 # This is normal operation
329 server = smtplib.SMTP(mta)
330 #server = smtplib.SMTP('golf.cs.princeton.edu')
331 server.sendmail(FROM, to, msg)
332 if config.bcc and not config.debug:
333 server.sendmail(FROM, config.email, msg)
335 except Exception, err:
336 print "Mailer error1: failed using MTA(%s) with: %s" % (mta, err)
338 elif not config.debug and not config.mail and config.bcc:
339 for mta in [MTA, 'golf.cs.princeton.edu']:
341 server = smtplib.SMTP(mta)
342 server.sendmail(FROM, to, msg)
344 except Exception, err:
345 print "Mailer error2: failed using MTA(%s) with: %s" % (mta, err)
347 #print "Would mail %s" %to
348 logger.debug("Would send mail to %s" % to)
350 if __name__=="__main__":
354 #email("[spam] bcc test from golf.cs.princeton.edu",
355 # "It gets to both recipients",
356 # "soltesz@cs.utk.edu")
357 #emailViaRT("rt via golf",
358 # "It gets to both recipients",
359 # "soltesz@cs.utk.edu")
360 email("Re: [PL #21323] TEST 7",
361 mailtxt.newbootcd_one[1] % {'hostname_list':"hostname list..."},
362 ['monitor@planet-lab.org'])
363 #print "ticketid: %d" % id
364 #id = plc.siteId(["alice.cs.princeton.edu"])
367 #email('TEST', emailTxt.mailtxt.ssh % {'hostname': "ALICE.cs.princeton.edu"}, "tech-" + id + "@sites.planet-lab.org")
370 #email("TEST111", "I'd like to see if this works anywhere", ["soltesz@cs.princeton.edu", "soltesz@cs.utk.edu"])
371 #print "mailer does nothing in main()"