def sendEmailAlert(self, sid, state, time_first_seen_in_new_state): ''' Sends an email to everyone in the global serverlink_alert_groups about the specified server-link's health problem. sid = sid of server which is unhealthy (int) state = int time = time first seen in this state (secs since epoc) ''' recipients = [] recipient_groups = xsftp.webui.models.Configuration.objects.all()[0].serverlink_alert_groups.all() for group in recipient_groups: for user in group.users.all(): if user not in recipients: recipients.append(user) email_addresses = [user.email for user in recipients if user.email] server_link = xsftp.webui.models.Server.objects.get(id=sid) server_link_name = server_link.server_name device_name = xsftp.webui.models.Configuration.objects.all()[0].device_name if not email_addresses: log(1, "Could not send Server Link Health warning email for Server '%s': No 'Server Link Health Global Alert Groups' have been specified." % server_link_name) # instantiate a new Server object, set its state, then extract its html details for that state. if server_link.status != state: server_link.status = state # generate text details, by converting the html healthstrings to text for email rendering. myWriter = formatter.DumbWriter() myFormatter = formatter.AbstractFormatter(myWriter) p = EmailTextParser(myFormatter) p.feed(server_link.healthStrings()) # remove tab characters details = p.data.replace('\t','') # remove blank lines details = "\n".join([line for line in details.split("\n") if line != '']) p.close() #details = server_link.healthStrings() # generate time string total_seconds = int(time.time() - time_first_seen_in_new_state) days = total_seconds / 86400 hours = total_seconds % 86400 / 3600 minutes = total_seconds % 86400 % 3600 / 60 seconds = total_seconds % 86400 % 3600 % 60 time_string = "%s days, %s hours, %s minutes, %s seconds" % (days, hours, minutes, seconds) message = ''' This is an automatic message from the Fcombine Device: %(device_name)s The Server Link '%(server_link_name)s' has been in unhealthy state %(state)s for %(time_string)s. arning - Jobs and Users may not be able to utilise this Server Link until it is repaired. See details below for help on remediating this issue. Details are: %(details)s ''' % {"device_name":device_name, "server_link_name":server_link_name, "state":state, "time_string":time_string, "details":details} try: email.send_email(subject="Fcombine Server Link Health warning for Server '%s'" % server_link_name, body=message, to=email_addresses) except Email_Error, e: log(1, "Could not send Server Link Health warning email for Server '%s': %s" % (server_link_name, e))
def render_to_email(self): recipients = list() if self.status: # Gather the 'alert on success' users # 1) Global Alert Users global_groups = xsftp.webui.models.Configuration.objects.all()[0].job_success_alert_groups.all() # global_groups is now just a list of groups # for each of those groups in global_groups, we want to get out all the users for group in global_groups: for user in group.users.all(): if user not in recipients: recipients.append(user) # 2) Job Specific Groups if not job_temp.suppress_group_alerts: job_groups = job_temp.alert_groups_on_success.all() for group in job_groups: for user in group.users.all(): if user not in recipients: recipients.append(user) # 3) Job Owner if job_temp.alert_owner_on_success and job_temp.owner not in recipients: recipients.append(job_temp.owner) else: # Gather the 'alert on fail' users # 1) Global Alert Users global_groups = xsftp.webui.models.Configuration.objects.all()[0].job_failure_alert_groups.all() # global_groups is now just a list of groups # for each of those groups in global_groups, we want to get out all the users for group in global_groups: for user in group.users.all(): if user not in recipients: recipients.append(user) # 2) Job Specific Groups if not job_temp.suppress_group_alerts: job_groups = job_temp.alert_groups_on_fail.all() for group in job_groups: for user in group.users.all(): if user not in recipients: recipients.append(user) # 3) Job Owner if job_temp.alert_owner_on_fail and job_temp.owner not in recipients: recipients.append(job_temp.owner) email_addresses = [user.email for user in recipients if user.email] # Generate some strings that will be used in the message # Duration String duration = self.end_time - self.start_time total_seconds = duration.seconds + (duration.days * 86400) hours = total_seconds / 3600 minutes = total_seconds % 3600 / 60 seconds = total_seconds % 3600 % 60 duration_string = "%002d:%002d:%002d" % (hours, minutes, seconds) # Data Transferred string if self.source_files: total_data = reduce(lambda x, y: x + y, [f.file_size for f in self.source_files if f.file_size is not None] or [0]) else: total_data = 0 total_data = int(total_data) if total_data / 1024**3: data = "%.2f GB" % (float(total_data)/1024**3) elif total_data / 1024**2: data = "%.2f MB" % (float(total_data)/1024**2) elif total_data / 1024: data = "%.2f KB" % (float(total_data)/1024) else: data = "%s bytes" % total_data if not self.source_files: data = "0 (no source files selected for copy)" # PreScript String if job.use_pre_script: pre_script_string = "\nPrescript: %s" % job.pre_script.script_name else: pre_script_string = "" if job_temp.use_post_script: post_script_string = "\nPostscript: %s" % job_temp.post_script.script_name else: post_script_string = "" # generate the message # generate message, starting with pre-script and postscript message blocks pre_script_block = post_script_block = "" if self.pre_script_output: pre_script_block = "\nPre-Script Output\n=================\n***** Return Code:\n%s\n***** Output Data (stdout):\n%s\n***** Output Data (stderr):\n%s\n" % ( self.pre_script_output[0], self.pre_script_output[1], (self.pre_script_output[2] or "None"), ) if self.post_script_output: post_script_block = "\nPost-Script Output\n==================\n***** Return Code:\n%s\n***** Output Data (stdout):\n%s\n***** Output Data (stderr):\n%s\n" % ( self.post_script_output[0], (self.post_script_output[1] or "None"), (self.post_script_output[2] or "None"), ) # generate full message message = """ This is an automatic message from Fcombine: %(device_name)s The Job '%(job_name)s' has %(statusString)s See attachment for per-file details. Job Information =============== Job Name: %(job_name)s Owner: %(owner)s Comment: %(comment)s Run Count: %(count)s%(prescript)s%(postscript)s %(runnow)s Transfer Details ================ Source Server Link: %(source)s Destination Server Link: %(dest)s Destination Path: %(dest_path)s Job Results =========== Status: %(status)s Message: %(message)s Start Time: %(start)s End Time: %(end)s Duration: %(dur)s Data Transfer Size: %(data)s %(pre_script_output)s %(post_script_output)s """ % { "device_name":xsftp.webui.models.Configuration.objects.all()[0].device_name, "job_name":job.job_name, "owner":job.owner.username, "comment":job.comment, "count":job.run_count, "prescript":pre_script_string, "postscript":post_script_string, "status":["Success", "Fail"][[True, False].index(self.status)], "statusString": ["COMPLETED SUCCESSFULLY.", "FAILED."][[True, False].index(self.status)], "message":self.message, "start":self.start_time.ctime(), "end":self.end_time.ctime(), "dur":duration_string, "data":data, "source":job_temp.source_server.server_name, "dest":job_temp.dest_server.server_name, "dest_path":job_temp.dest_path, "runnow":["", "This job was invoked manually"][self.runnow], "pre_script_output":pre_script_block, "post_script_output":post_script_block, } # generate the attachment content attachment_content = """Source Files,Destination File Name,Size (bytes),Attempted,Status,Start Time,End Time,Duration (seconds),Message\n""" source_strip = len(xsftp.common.constants.SMP_DIR + str(job_temp.source_server.id)) dest_strip = len(xsftp.common.constants.SMP_DIR + str(job_temp.dest_server.id)) for f in self.source_files: sourceString = "%s:%s" % (job_temp.source_server.server_name, f.src_path[source_strip:]) if f.dest_path: destString = "%s:%s" % (job_temp.dest_server.server_name, f.dest_path[dest_strip:]) else: destString = "None" if f.start_time: start_string = f.start_time.ctime() else: start_string = "" if f.end_time: end_string = f.end_time.ctime() else: end_string = "" if f.end_time: duration = (f.end_time - f.start_time).seconds else: duration = None attachment_content += """%(src)s,%(dest)s,%(size)s,%(attempted)s,%(status)s,%(start)s,%(end)s,%(dur)s,%(msg)s\n""" % {"src":sourceString, "dest":destString, "size":f.file_size, "status":["Pass", "Fail"][[True, False].index(f.status)], "attempted":["Yes", "No"][[True, False].index(f.attempted)], "start":start_string, "end":end_string, "dur":duration, "msg":f.message or ""} try: email.send_email(subject="Fcombine Job Report for job '%s': %s" % (job.job_name, ["SUCCESS", "FAIL"][[True, False].index(self.status)]), body=message, to=email_addresses, attachments=[('Fcombine_Job_Details.csv', attachment_content, 'text/csv')]) except xsftp.webui.constants.Email_Error, e: log("Error sending email report for job '%s': %s" % (job.job_name, e))