def build_email_body(ctx, stack, sleep_time_sec): email_template_path = os.path.dirname(__file__) + \ '/templates/email-sleep-before-teardown.jinja2' with open(email_template_path) as f: template_text = f.read() email_template = jinja2.Template(template_text) archive_path = ctx.config.get('archive_path') job_id = ctx.config.get('job_id') status = get_status(ctx.summary) stack_path = '/'.join(task for task, _ in stack) suite_name = ctx.config.get('suite') sleep_date = time.time() sleep_date_str = time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(sleep_date)) body = email_template.render( sleep_time=format_timespan(sleep_time_sec), sleep_time_sec=sleep_time_sec, sleep_date=sleep_date_str, owner=ctx.owner, run_name=ctx.name, job_id=ctx.config.get('job_id'), job_info=get_results_url(ctx.name), job_logs=get_http_log_path(archive_path, job_id), suite_name=suite_name, status=status, task_stack=stack_path, ) subject = ('teuthology job {run}/{job} has fallen asleep at {date}'.format( run=ctx.name, job=job_id, date=sleep_date_str)) return (subject.strip(), body.strip())
def build_rocketchat_message(ctx, stack, sleep_time_sec, template_path=None): message_template_path = template_path or os.path.dirname(__file__) + \ '/templates/rocketchat-sleep-before-teardown.jinja2' with open(message_template_path) as f: template_text = f.read() template = jinja2.Template(template_text) archive_path = ctx.config.get('archive_path') job_id = ctx.config.get('job_id') status = get_status(ctx.summary) stack_path = ' -> '.join(task for task, _ in stack) suite_name = ctx.config.get('suite') sleep_date = time.time() sleep_date_str = time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(sleep_date)) message = template.render( sleep_time=format_timespan(sleep_time_sec), sleep_time_sec=sleep_time_sec, sleep_date=sleep_date_str, owner=ctx.owner, run_name=ctx.name, job_id=ctx.config.get('job_id'), job_desc=ctx.config.get('description'), job_info=get_results_url(ctx.name, job_id), job_logs=get_http_log_path(archive_path, job_id), suite_name=suite_name, status=status, task_stack=stack_path, ) return message
def build_email_body(name, _reporter=None): stanzas = OrderedDict([ ('fail', dict()), ('dead', dict()), ('running', dict()), ('waiting', dict()), ('queued', dict()), ('pass', dict()), ]) reporter = _reporter or ResultsReporter() fields = ('job_id', 'status', 'description', 'duration', 'failure_reason', 'sentry_event', 'log_href') jobs = reporter.get_jobs(name, fields=fields) jobs.sort(key=lambda job: job['job_id']) for job in jobs: job_stanza = format_job(name, job) stanzas[job['status']][job['job_id']] = job_stanza sections = OrderedDict.fromkeys(stanzas.keys(), '') subject_fragments = [] for status in sections.keys(): stanza = stanzas[status] if stanza: subject_fragments.append('%s %s' % (len(stanza), status)) sections[status] = email_templates['sect_templ'].format( title=status.title(), jobs=''.join(stanza.values()), ) subject = ', '.join(subject_fragments) + ' ' if config.archive_server: log_root = os.path.join(config.archive_server, name, '') else: log_root = None body = email_templates['body_templ'].format( name=name, info_root=misc.get_results_url(name), log_root=log_root, fail_count=len(stanzas['fail']), dead_count=len(stanzas['dead']), running_count=len(stanzas['running']), waiting_count=len(stanzas['waiting']), queued_count=len(stanzas['queued']), pass_count=len(stanzas['pass']), fail_sect=sections['fail'], dead_sect=sections['dead'], running_sect=sections['running'], waiting_sect=sections['waiting'], queued_sect=sections['queued'], pass_sect=sections['pass'], ) subject += 'in {suite}'.format(suite=name) return (subject.strip(), body.strip())
def write_result(self): arg = copy.deepcopy(self.base_args) arg.append('--last-in-suite') if self.base_config.email: arg.extend(['--email', self.base_config.email]) if self.args.timeout: arg.extend(['--timeout', self.args.timeout]) util.teuthology_schedule(args=arg, dry_run=self.args.dry_run, verbose=self.args.verbose, log_prefix="Results: ") results_url = get_results_url(self.base_config.name) if results_url: log.info("Test results viewable at %s", results_url)
def format_job(run_name, job): job_id = job['job_id'] status = job['status'] description = job['description'] duration = seconds_to_hms(int(job['duration'] or 0)) # Every job gets a link to e.g. pulpito's pages info_url = misc.get_results_url(run_name, job_id) if info_url: info_line = email_templates['info_url_templ'].format(info=info_url) else: info_line = '' if status in UNFINISHED_STATUSES: format_args = dict( job_id=job_id, desc=description, time=duration, info_line=info_line, ) return email_templates['running_templ'].format(**format_args) if status == 'pass': return email_templates['pass_templ'].format( job_id=job_id, desc=description, time=duration, info_line=info_line, ) else: log_dir_url = job['log_href'].rstrip('teuthology.yaml') if log_dir_url: log_line = email_templates['fail_log_templ'].format( log=log_dir_url) else: log_line = '' sentry_event = job.get('sentry_event') if sentry_event: sentry_line = email_templates['fail_sentry_templ'].format( sentry_event=sentry_event) else: sentry_line = '' if job['failure_reason']: # 'fill' is from the textwrap module and it collapses a given # string into multiple lines of a maximum width as specified. # We want 75 characters here so that when we indent by 4 on the # next line, we have 79-character exception paragraphs. reason = fill(job['failure_reason'] or '', 75) reason = \ '\n'.join((' ') + line for line in reason.splitlines()) reason_lines = email_templates['fail_reason_templ'].format( reason=reason).rstrip() else: reason_lines = '' format_args = dict( job_id=job_id, desc=description, time=duration, info_line=info_line, log_line=log_line, sentry_line=sentry_line, reason_lines=reason_lines, ) return email_templates['fail_templ'].format(**format_args)
def build_email_body(name, archive_dir, timeout): failed = {} hung = {} passed = {} for job in ls.get_jobs(archive_dir): job_dir = os.path.join(archive_dir, job) summary_file = os.path.join(job_dir, 'summary.yaml') # Every job gets a link to e.g. pulpito's pages info_url = misc.get_results_url(name, job) if info_url: info_line = email_templates['info_url_templ'].format(info=info_url) else: info_line = '' # Unfinished jobs will have no summary.yaml if not os.path.exists(summary_file): info_file = os.path.join(job_dir, 'info.yaml') desc = '' if os.path.exists(info_file): with file(info_file) as f: info = yaml.safe_load(f) desc = info['description'] hung[job] = email_templates['hung_templ'].format( job_id=job, desc=desc, info_line=info_line, ) continue with file(summary_file) as f: summary = yaml.safe_load(f) if summary['success']: passed[job] = email_templates['pass_templ'].format( job_id=job, desc=summary.get('description'), time=int(summary.get('duration', 0)), info_line=info_line, ) else: log = misc.get_http_log_path(archive_dir, job) if log: log_line = email_templates['fail_log_templ'].format(log=log) else: log_line = '' # Transitioning from sentry_events -> sentry_event sentry_events = summary.get('sentry_events') if sentry_events: sentry_event = sentry_events[0] else: sentry_event = summary.get('sentry_event', '') if sentry_event: sentry_line = email_templates['fail_sentry_templ'].format( sentry_event=sentry_event) else: sentry_line = '' # 'fill' is from the textwrap module and it collapses a given # string into multiple lines of a maximum width as specified. We # want 75 characters here so that when we indent by 4 on the next # line, we have 79-character exception paragraphs. reason = fill(summary.get('failure_reason'), 75) reason = '\n'.join((' ') + line for line in reason.splitlines()) failed[job] = email_templates['fail_templ'].format( job_id=job, desc=summary.get('description'), time=int(summary.get('duration', 0)), reason=reason, info_line=info_line, log_line=log_line, sentry_line=sentry_line, ) maybe_comma = lambda s: ', ' if s else ' ' subject = '' fail_sect = '' hung_sect = '' pass_sect = '' if failed: subject += '{num_failed} failed{sep}'.format( num_failed=len(failed), sep=maybe_comma(hung or passed) ) fail_sect = email_templates['sect_templ'].format( title='Failed', jobs=''.join(failed.values()) ) if hung: subject += '{num_hung} hung{sep}'.format( num_hung=len(hung), sep=maybe_comma(passed), ) hung_sect = email_templates['sect_templ'].format( title='Hung', jobs=''.join(hung.values()), ) if passed: subject += '%s passed ' % len(passed) pass_sect = email_templates['sect_templ'].format( title='Passed', jobs=''.join(passed.values()), ) body = email_templates['body_templ'].format( name=name, info_root=misc.get_results_url(name), log_root=misc.get_http_log_path(archive_dir), fail_count=len(failed), hung_count=len(hung), pass_count=len(passed), fail_sect=fail_sect, hung_sect=hung_sect, pass_sect=pass_sect, ) subject += 'in {suite}'.format(suite=name) return (subject.strip(), body.strip())
def build_email_body(name, archive_dir): failed = {} hung = {} passed = {} for job in ls.get_jobs(archive_dir): job_dir = os.path.join(archive_dir, job) summary_file = os.path.join(job_dir, 'summary.yaml') # Every job gets a link to e.g. pulpito's pages info_url = misc.get_results_url(name, job) if info_url: info_line = email_templates['info_url_templ'].format(info=info_url) else: info_line = '' # Unfinished jobs will have no summary.yaml if not os.path.exists(summary_file): info_file = os.path.join(job_dir, 'info.yaml') desc = '' if os.path.exists(info_file): with file(info_file) as f: info = yaml.safe_load(f) desc = info['description'] hung[job] = email_templates['hung_templ'].format( job_id=job, desc=desc, info_line=info_line, ) continue with file(summary_file) as f: summary = yaml.safe_load(f) if get_status(summary) == 'pass': passed[job] = email_templates['pass_templ'].format( job_id=job, desc=summary.get('description'), time=int(summary.get('duration', 0)), info_line=info_line, ) else: log = misc.get_http_log_path(archive_dir, job) if log: log_line = email_templates['fail_log_templ'].format(log=log) else: log_line = '' # Transitioning from sentry_events -> sentry_event sentry_events = summary.get('sentry_events') if sentry_events: sentry_event = sentry_events[0] else: sentry_event = summary.get('sentry_event', '') if sentry_event: sentry_line = email_templates['fail_sentry_templ'].format( sentry_event=sentry_event) else: sentry_line = '' # 'fill' is from the textwrap module and it collapses a given # string into multiple lines of a maximum width as specified. We # want 75 characters here so that when we indent by 4 on the next # line, we have 79-character exception paragraphs. reason = fill(summary.get('failure_reason'), 75) reason = '\n'.join((' ') + line for line in reason.splitlines()) failed[job] = email_templates['fail_templ'].format( job_id=job, desc=summary.get('description'), time=int(summary.get('duration', 0)), reason=reason, info_line=info_line, log_line=log_line, sentry_line=sentry_line, ) maybe_comma = lambda s: ', ' if s else ' ' subject = '' fail_sect = '' hung_sect = '' pass_sect = '' if failed: subject += '{num_failed} failed{sep}'.format(num_failed=len(failed), sep=maybe_comma( hung or passed)) fail_sect = email_templates['sect_templ'].format(title='Failed', jobs=''.join( failed.values())) if hung: subject += '{num_hung} hung{sep}'.format( num_hung=len(hung), sep=maybe_comma(passed), ) hung_sect = email_templates['sect_templ'].format( title='Hung', jobs=''.join(hung.values()), ) if passed: subject += '%s passed ' % len(passed) pass_sect = email_templates['sect_templ'].format( title='Passed', jobs=''.join(passed.values()), ) body = email_templates['body_templ'].format( name=name, info_root=misc.get_results_url(name), log_root=misc.get_http_log_path(archive_dir), fail_count=len(failed), hung_count=len(hung), pass_count=len(passed), fail_sect=fail_sect, hung_sect=hung_sect, pass_sect=pass_sect, ) subject += 'in {suite}'.format(suite=name) return (subject.strip(), body.strip())