Changes necessary for the new operating environment. rt_tickets, returns empty strin...
[monitor.git] / mailer.py
1 #!/usr/bin/python2
2 #
3 # Copyright (c) 2004  The Trustees of Princeton University (Trustees).
4 #
5 # Faiyaz Ahmed <faiyaza@cs.princeton.edu>
6 #
7 # $Id: mailer.py,v 1.10 2007/08/08 13:28:06 soltesz Exp $
8 from emailTxt import *
9 import smtplib
10 from config import config
11 import logging
12 import os
13 import time
14
15 config = config()
16 logger = logging.getLogger("monitor")
17
18 MTA="localhost"
19 FROM="monitor@planet-lab.org"
20
21 def reformat_for_rt(text):
22         lines = text.split("\n")
23         spaced_text = ""
24         for line in lines:
25                 spaced_text += " %s\n" %line
26         return spaced_text
27                 
28
29 def _setupRTenvironment():
30         os.environ['PATH'] = os.environ['PATH'] + ":/home/soltesz/local/bin/"
31         os.environ['RTSERVER'] = "https://rt.planet-lab.org/"
32         os.environ['RTUSER']   = "monitor"
33         os.environ['RTPASSWD'] = "ssorcmor"
34         os.environ['RTDEBUG'] = "0"
35         return
36
37 def setAdminCCViaRT(ticket_id, to):
38         # Set ENV Variables/PATH
39         _setupRTenvironment()
40         if ticket_id == None or ticket_id == "":
41                 raise Exception("ERROR: ticket_id must be set to some integer value")
42
43         # This will raise an exception if it is not a valid id.
44         i_ticket_id = int(ticket_id)
45
46         # create a comma-separated list
47         s_to = ",".join(to)
48         cmd = "rt edit ticket/%s set admincc='%s'" % (ticket_id, s_to)
49         (f_in, f_out, f_err) = os.popen3(cmd)
50         value = f_out.read()
51         l_values = value.split()
52         f_in.close() ; f_out.close() ; f_err.close()
53         if len(l_values) > 3 and "updated" in l_values[3]:
54                 # Success
55                 pass
56         else:
57                 print "VALUE:", value
58                 print "ERROR: RT failed to update AdminCC for ticket %s" % ticket_id
59
60         return
61
62 def setSubjectViaRT(ticket_id, subject):
63         # Set ENV Variables/PATH
64         _setupRTenvironment()
65         if ticket_id == None or ticket_id == "":
66                 raise Exception("ERROR: ticket_id must be set to some integer value")
67
68         # This will raise an exception if it is not a valid id.
69         i_ticket_id = int(ticket_id)
70
71         cmd = "rt edit ticket/%s set subject='%s'" % (ticket_id, subject)
72         (f_in, f_out, f_err) = os.popen3(cmd)
73         value = f_out.read()
74         l_values = value.split()
75         f_in.close() ; f_out.close() ; f_err.close()
76         if len(l_values) > 3 and "updated" in l_values[3]:
77                 # Success
78                 pass
79         else:
80                 print "VALUE:", value
81                 print "ERROR: RT failed to update subject for ticket %s" % ticket_id
82
83         return
84                 
85
86 def addCommentViaRT(ticket_id, comment):
87         # Set ENV Variables/PATH
88         _setupRTenvironment()
89         if ticket_id == None or ticket_id == "":
90                 raise Exception("ERROR: ticket_id must be set to some integer value")
91
92         # This will raise an exception if it is not a valid id.
93         i_ticket_id = int(ticket_id)
94
95         cmd = "rt comment -m '%s' ticket/%s" % (comment, i_ticket_id)
96         (f_in, f_out, f_err) = os.popen3(cmd)
97         value = f_out.read()
98         l_values = value.split()
99         f_in.close() ; f_out.close() ; f_err.close()
100         if len(l_values) > 1 and "recorded" in l_values[1]:
101                 # Success
102                 pass
103         else:
104                 # Error
105                 f_in.close() ; f_out.close() ; f_err.close()
106                 print "ERROR: RT failed to add comment to id %s" % ticket_id
107
108         return
109
110 def closeTicketViaRT(ticket_id, comment):
111         # Set ENV Variables/PATH
112         _setupRTenvironment()
113         if ticket_id == None or ticket_id == "":
114                 raise Exception("ERROR: ticket_id must be set to some integer value")
115
116         # This will raise an exception if it is not a valid id.
117         i_ticket_id = int(ticket_id)
118
119         # Append comment to RT ticket
120         addCommentViaRT(ticket_id, comment)
121
122         if not config.debug:
123                 cmd = "rt edit ticket/%s set status=resolved" % i_ticket_id
124                 (f_in, f_out, f_err) = os.popen3(cmd)
125                 f_in.close()
126                 value = f_out.read()
127                 f_out.close()
128                 f_err.close()
129                 l_values = value.split()
130                 if len(l_values) >= 4 and "updated" in l_values[3]:
131                         # Success!!
132                         pass
133                 else:
134                         print "VALUE: ", value
135                         # Failed!!
136                         print "FAILED to resolve Ticket %s" % ticket_id
137                         print "FAILED to resolve Ticket %s" % i_ticket_id
138
139         return
140
141 def emailViaRT(subject, text, to, ticket_id=None):
142         if ticket_id == None or ticket_id == "":
143                 return emailViaRT_NoTicket(subject, text, to)
144                 
145
146         # Set ENV Variables/PATH
147         _setupRTenvironment()
148
149         if config.mail and not config.debug:
150                 setSubjectViaRT(ticket_id, subject)
151                 setAdminCCViaRT(ticket_id, to)
152
153                 cmd = "rt correspond -m - %s" % ticket_id
154                 (f_in, f_out, f_err) = os.popen3(cmd)
155                 f_in.write(text)
156                 f_in.flush()
157                 f_in.close()
158                 value = f_out.read()
159
160                 # TODO: rt doesn't write to stderr on error!!!
161                 if value == "":
162                         raise Exception, f_err.read()
163
164                 del f_in
165                 f_out.close(); del f_out
166                 f_err.close(); del f_err
167                 os.wait()
168
169         return ticket_id
170         
171
172 def emailViaRT_NoTicket(subject, text, to):
173         """Use RT command line tools to send email.
174                 return the generated RT ticket ID number.
175         """
176         i_ticket = 0
177
178         if config.mail and config.debug:
179                 to = [config.email]
180
181         # Set ENV Variables/PATH
182         _setupRTenvironment()
183
184         # NOTE: AdminCc: (in PLC's RT configuration) gets an email sent.
185         # This is not the case (surprisingly) for Cc:
186         input_text  = "Subject: %s\n"
187         input_text += "Requestor: monitor@planet-lab.org\n"
188         input_text += "id: ticket/new\n"
189         input_text += "Queue: Monitor\n"
190         for recipient in to:
191                 input_text += "AdminCc: %s\n" % recipient
192         input_text += "Text: %s"
193
194         # Add a space for each new line to get RT to accept the file.
195         spaced_text = reformat_for_rt(text)
196
197         if config.mail and not config.debug:
198                 cmd = "rt create -i -t ticket"
199                 (f_in, f_out, f_err) = os.popen3(cmd)
200                 f_in.write(input_text % (subject, spaced_text))
201                 f_in.flush()
202                 f_in.close()
203                 value = f_out.read()
204
205                 # TODO: rt doesn't write to stderr on error!!!
206                 if value == "":
207                         raise Exception, f_err.read()
208
209                 print "MAILER: ticket value == %s" % value.split()[2]
210                 i_ticket = int(value.split()[2])
211                 # clean up the child process.
212                 f_in.close();  del f_in
213                 f_out.close(); del f_out
214                 f_err.close(); del f_err
215                 os.wait()
216         elif config.mail and config.debug:
217                 email(subject, spaced_text, to)
218                 i_ticket = 0
219         else:
220                 i_ticket = 0
221
222         return i_ticket
223
224 def email(subject, text, to):
225         """Create a mime-message that will render HTML in popular
226         MUAs, text in better ones"""
227         import MimeWriter
228         import mimetools
229         import cStringIO
230
231         if (config.mail and config.debug) or (not config.mail and not config.debug and config.bcc):
232                 to = [config.email]
233
234         out = cStringIO.StringIO() # output buffer for our message 
235         txtin = cStringIO.StringIO(text)
236
237         writer = MimeWriter.MimeWriter(out)
238         #
239         # set up some basic headers... we put subject here
240         # because smtplib.sendmail expects it to be in the
241         # message body
242         #
243         writer.addheader("Subject", subject)
244         if to.__class__ == [].__class__ :       
245                 writer.addheader("To", to[0])
246                 cc = ""
247                 for dest in to[1:len(to)]:
248                         cc +="%s, " % dest
249                 cc = cc.rstrip(", ") 
250                 writer.addheader("Cc", cc)
251         else:
252                 writer.addheader("To", to)
253
254         if config.bcc and not config.debug:
255                 writer.addheader("Bcc", config.email)
256
257         writer.addheader("Reply-To", 'monitor@planet-lab.org')
258                 
259         writer.addheader("MIME-Version", "1.0")
260         #
261         # start the multipart section of the message
262         # multipart/alternative seems to work better
263         # on some MUAs than multipart/mixed
264         #
265         writer.startmultipartbody("alternative")
266         writer.flushheaders()
267         #
268         # the plain text section
269         #
270         subpart = writer.nextpart()
271         subpart.addheader("Content-Transfer-Encoding", "quoted-printable")
272         pout = subpart.startbody("text/plain", [("charset", 'us-ascii')])
273         mimetools.encode(txtin, pout, 'quoted-printable')
274         txtin.close()
275         #
276         # Now that we're done, close our writer and
277         # return the message body
278         #
279         writer.lastpart()
280         msg = out.getvalue()
281         out.close()
282
283         # three cases:
284         #       mail but no-debug
285         #       mail and debug, 'to' changed at the beginning'
286         #   nomail, but report who I'd send to.
287         if config.mail:
288                 try:
289                         # This is normal operation
290                         server = smtplib.SMTP(MTA)
291                         server.sendmail(FROM, to,  msg)
292                         if config.bcc and not config.debug:
293                                 server.sendmail(FROM, config.email,  msg)
294                         server.quit()
295                 except Exception, err:
296                         print "Mailer error: %s" % err
297         elif not config.debug and not config.mail and config.bcc:
298                 try:
299                         server = smtplib.SMTP(MTA)
300                         server.sendmail(FROM, to,  msg)
301                         server.quit()
302                 except Exception, err:
303                         print "Mailer error: %s" % err
304         else:
305                 #print "Would mail %s" %to
306                 logger.debug("Would send mail to %s" % to)
307
308 if __name__=="__main__":
309         import smtplib
310         import emailTxt
311         import plc 
312         #email("[spam] bcc test from golf.cs.princeton.edu", 
313         #         "It gets to both recipients", 
314         #         "soltesz@cs.utk.edu")
315         #emailViaRT("rt via golf", 
316         #         "It gets to both recipients", 
317         #         "soltesz@cs.utk.edu")
318         email("Re: [PL #21323] TEST 7", 
319                            mailtxt.newbootcd_one[1] % {'hostname_list':"hostname list..."},
320                            ['monitor@planet-lab.org'])
321         #print "ticketid: %d" % id
322         #id = plc.siteId(["alice.cs.princeton.edu"])
323         #print id
324         #if id:
325                 #email('TEST', emailTxt.mailtxt.ssh % {'hostname': "ALICE.cs.princeton.edu"}, "tech-" + id + "@sites.planet-lab.org")
326         #else:
327         #       print "No dice."
328         #email("TEST111", "I'd like to see if this works anywhere", ["soltesz@cs.princeton.edu", "soltesz@cs.utk.edu"])
329         #print "mailer does nothing in main()"