# bury the job so it won't be re-run if it fails
job.bury()
+ log.debug('Reserved job %d', job.jid)
log.debug('Config is: %s', job.body)
job_config = yaml.safe_load(job.body)
-
- log.debug('Creating archive dir...')
safe_archive = safepath.munge(job_config['name'])
- safepath.makedirs(ctx.archive_dir, safe_archive)
- archive_path = os.path.join(ctx.archive_dir, safe_archive, str(job.jid))
- log.info('Running job %d', job.jid)
- run_job(job_config, archive_path)
- job.delete()
+ if job_config.get('last_in_suite', False):
+ log.debug('Generating coverage for %s', job_config['name'])
+ subprocess.Popen(
+ args=[
+ os.path.join(os.path.dirname(sys.argv[0]), 'teuthology-results'),
+ '--timeout',
+ job_config.get('results_timeout', '21600'),
+ '--email',
+ job_config['email'],
+ '--archive-dir',
+ os.path.join(ctx.archive_dir, safe_archive),
+ '--name',
+ job_config['name'],
+ ])
+ else:
+ log.debug('Creating archive dir...')
+ safepath.makedirs(ctx.archive_dir, safe_archive)
+ archive_path = os.path.join(ctx.archive_dir, safe_archive, str(job.jid))
+ log.info('Running job %d', job.jid)
+ run_job(job_config, archive_path)
+ job.delete()
def run_job(job_config, archive_path):
arg = [
import argparse
+import copy
import errno
import itertools
import logging
import os
import subprocess
import sys
+import time
+import yaml
+
+from teuthology import misc as teuthology
log = logging.getLogger(__name__)
help='name for this suite',
required=True,
)
+ parser.add_argument(
+ '--email',
+ help='address to email test failures to',
+ )
+ parser.add_argument(
+ '--timeout',
+ help='how many seconds to wait for jobs to finish before emailing results',
+ )
parser.add_argument(
'config',
metavar='CONFFILE',
# degenerate case; 'suite' is actually a single collection
collections = [(args.suite, 'none')]
+ base_arg = [
+ os.path.join(os.path.dirname(sys.argv[0]), 'teuthology-schedule'),
+ '--name', args.name,
+ ]
+ if args.verbose:
+ base_arg.append('-v')
+ if args.owner:
+ base_arg.extend(['--owner', args.owner])
+
for collection, collection_name in sorted(collections):
log.info('Collection %s in %s' % (collection_name, collection))
facets = [
log.info(
'Running teuthology-schedule with facets %s', description
)
- arg = [
- os.path.join(os.path.dirname(sys.argv[0]), 'teuthology-schedule'),
- ]
-
- if args.verbose:
- arg.append('-v')
-
- if args.owner:
- arg.extend(['--owner', args.owner])
-
+ arg = copy.deepcopy(base_arg)
arg.extend([
- '--name', args.name,
'--description', description,
'--',
])
-
arg.extend(path for facet, name, path in configs)
arg.extend(args.config)
print arg
args=arg,
)
+ arg = copy.deepcopy(base_arg)
+ arg.append('--last-in-suite')
+ if args.email:
+ arg.extend(['--email', args.email])
+ if args.timeout:
+ arg.extend(['--timeout', args.timeout])
+ subprocess.check_call(
+ args=arg
+ )
+
def ls():
parser = argparse.ArgumentParser(description='List teuthology job results')
parser.add_argument(
)
args = parser.parse_args()
- import yaml
-
for j in sorted(os.listdir(args.archive_dir)):
if j.startswith('.'):
continue
desc=summary.get('description', '-'),
success='pass' if summary['success'] else 'FAIL',
)
+
+def results():
+ parser = argparse.ArgumentParser(description='Email teuthology suite results')
+ parser.add_argument(
+ '--email',
+ help='address to email test failures to',
+ )
+ parser.add_argument(
+ '--timeout',
+ help='how many seconds to wait for all tests to finish (default no wait)',
+ type=int,
+ default=0,
+ )
+ parser.add_argument(
+ '--archive-dir',
+ metavar='DIR',
+ help='path under which results for the suite are stored',
+ required=True,
+ )
+ parser.add_argument(
+ '--name',
+ help='name of the suite',
+ required=True,
+ )
+ parser.add_argument(
+ '-v', '--verbose',
+ action='store_true', default=False,
+ help='be more verbose',
+ )
+ args = parser.parse_args()
+
+ loglevel = logging.INFO
+ if args.verbose:
+ loglevel = logging.DEBUG
+
+ logging.basicConfig(
+ level=loglevel,
+ )
+
+ teuthology.read_config(args)
+
+ running_tests = [
+ f for f in sorted(os.listdir(args.archive_dir))
+ if not f.startswith('.')
+ and not os.path.exists(os.path.join(args.archive_dir, f, 'summary.yaml'))
+ ]
+ starttime = time.time()
+ while running_tests and args.timeout > 0:
+ if os.path.exists(os.path.join(
+ args.archive_dir,
+ running_tests[-1], 'summary.yaml')):
+ running_tests.pop()
+ else:
+ if time.time() - starttime > args.timeout:
+ log.warn('test(s) did not finish before timeout of %d seconds',
+ args.timeout)
+ break
+ time.sleep(10)
+
+ subprocess.Popen(
+ args=[
+ os.path.join(os.path.dirname(sys.argv[0]), 'teuthology-coverage'),
+ '-v',
+ '-o',
+ os.path.join(args.teuthology_config['coverage_output_dir'], args.name),
+ '--html-output',
+ os.path.join(args.teuthology_config['coverage_html_dir'], args.name),
+ '--cov-tools-dir',
+ args.teuthology_config['coverage_tools_dir'],
+ args.archive_dir,
+ ],
+ )
+
+ failures = []
+ unfinished = []
+ for j in sorted(os.listdir(args.archive_dir)):
+ if j.startswith('.'):
+ continue
+ summary_fn = os.path.join(args.archive_dir, j, 'summary.yaml')
+ if not os.path.exists(summary_fn):
+ unfinished.append(j)
+ continue
+ summary = {}
+ with file(summary_fn) as f:
+ g = yaml.safe_load_all(f)
+ for new in g:
+ summary.update(new)
+ if not summary['success']:
+ failures.append('{test}: {desc}'.format(
+ desc=summary['description'],
+ test=j,
+ ))
+ if (not failures and not unfinished) or not args.email:
+ return
+
+ import smtplib
+ from email.mime.text import MIMEText
+ msg = MIMEText("""
+The following tests failed:
+
+{failures}
+
+These tests may be hung (did not finish in {timeout} seconds after the last test in the suite):
+{unfinished}""".format(
+ failures='\n'.join(failures),
+ unfinished='\n'.join(unfinished),
+ timeout=args.timeout,
+ ))
+ msg['Subject'] = '{num_failed} failed and {num_hung} possibly hung tests in {suite}'.format(
+ num_failed=len(failures),
+ num_hung=len(unfinished),
+ suite=args.name,
+ )
+ msg['From'] = args.teuthology_config['results_sending_email']
+ msg['To'] = args.email
+ log.debug('sending email %s', msg.as_string())
+ smtp = smtplib.SMTP('localhost')
+ smtp.sendmail(msg['From'], [msg['To']], msg.as_string())
+ smtp.quit()