mirror of
https://github.com/ceph/ceph
synced 2025-01-31 07:22:56 +00:00
e0594ee69a
Signed-off-by: Zack Cerza <zack.cerza@inktank.com>
215 lines
6.8 KiB
Python
215 lines
6.8 KiB
Python
import os
|
|
import yaml
|
|
import StringIO
|
|
import contextlib
|
|
import sys
|
|
import logging
|
|
from traceback import format_tb
|
|
|
|
import teuthology
|
|
from . import report
|
|
from .misc import get_user
|
|
from .misc import read_config
|
|
from .nuke import nuke
|
|
from .run_tasks import run_tasks
|
|
from .repo_utils import fetch_qa_suite
|
|
from .results import email_results
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
def set_up_logging(ctx):
|
|
if ctx.verbose:
|
|
teuthology.log.setLevel(logging.DEBUG)
|
|
|
|
if ctx.archive is not None:
|
|
os.mkdir(ctx.archive)
|
|
|
|
teuthology.setup_log_file(os.path.join(ctx.archive, 'teuthology.log'))
|
|
|
|
install_except_hook()
|
|
|
|
|
|
def install_except_hook():
|
|
def log_exception(exception_class, exception, traceback):
|
|
logging.critical(''.join(format_tb(traceback)))
|
|
if not exception.message:
|
|
logging.critical(exception_class.__name__)
|
|
return
|
|
logging.critical('{0}: {1}'.format(
|
|
exception_class.__name__, exception))
|
|
|
|
sys.excepthook = log_exception
|
|
|
|
|
|
def write_initial_metadata(ctx):
|
|
if ctx.archive is not None:
|
|
with file(os.path.join(ctx.archive, 'pid'), 'w') as f:
|
|
f.write('%d' % os.getpid())
|
|
|
|
with file(os.path.join(ctx.archive, 'owner'), 'w') as f:
|
|
f.write(ctx.owner + '\n')
|
|
|
|
with file(os.path.join(ctx.archive, 'orig.config.yaml'), 'w') as f:
|
|
yaml.safe_dump(ctx.config, f, default_flow_style=False)
|
|
|
|
info = {
|
|
'name': ctx.name,
|
|
'description': ctx.description,
|
|
'owner': ctx.owner,
|
|
'pid': os.getpid(),
|
|
}
|
|
if 'job_id' in ctx.config:
|
|
info['job_id'] = ctx.config['job_id']
|
|
|
|
with file(os.path.join(ctx.archive, 'info.yaml'), 'w') as f:
|
|
yaml.safe_dump(info, f, default_flow_style=False)
|
|
|
|
|
|
def fetch_tasks_if_needed(job_config):
|
|
"""
|
|
Fetch the suite repo (and include it in sys.path) so that we can use its
|
|
tasks.
|
|
"""
|
|
# Any scheduled job will already have the suite checked out and its
|
|
# $PYTHONPATH set. We can check for this by looking for 'suite_path'
|
|
# in its config.
|
|
suite_path = job_config.get('suite_path')
|
|
if suite_path:
|
|
log.info("suite_path is set to %s; will attempt to use it", suite_path)
|
|
if suite_path not in sys.path:
|
|
sys.path.insert(1, suite_path)
|
|
|
|
try:
|
|
import tasks
|
|
log.info("Found tasks at %s", os.path.dirname(tasks.__file__))
|
|
return
|
|
except ImportError:
|
|
log.info("Tasks not found; will attempt to fetch")
|
|
|
|
ceph_branch = job_config.get('branch', 'master')
|
|
suite_branch = job_config.get('suite_branch', ceph_branch)
|
|
suite_path = fetch_qa_suite(suite_branch)
|
|
sys.path.insert(1, suite_path)
|
|
job_config['suite_path'] = suite_path
|
|
|
|
|
|
def main(ctx):
|
|
set_up_logging(ctx)
|
|
|
|
if ctx.owner is None:
|
|
ctx.owner = get_user()
|
|
|
|
# Older versions of teuthology stored job_id as an int. Convert it to a str
|
|
# if necessary.
|
|
job_id = ctx.config.get('job_id')
|
|
if job_id is not None:
|
|
job_id = str(job_id)
|
|
ctx.config['job_id'] = job_id
|
|
|
|
write_initial_metadata(ctx)
|
|
report.try_push_job_info(ctx.config, dict(status='running'))
|
|
|
|
if 'targets' in ctx.config and 'roles' in ctx.config:
|
|
targets = len(ctx.config['targets'])
|
|
roles = len(ctx.config['roles'])
|
|
assert targets >= roles, \
|
|
'%d targets are needed for all roles but found %d listed.' % (
|
|
roles, targets)
|
|
|
|
machine_type = ctx.machine_type
|
|
if machine_type is None:
|
|
fallback_default = ctx.config.get('machine_type', 'plana')
|
|
machine_type = ctx.config.get('machine-type', fallback_default)
|
|
|
|
if ctx.block:
|
|
assert ctx.lock, \
|
|
'the --block option is only supported with the --lock option'
|
|
|
|
read_config(ctx)
|
|
|
|
log.debug('\n '.join(['Config:', ] + yaml.safe_dump(
|
|
ctx.config, default_flow_style=False).splitlines()))
|
|
|
|
ctx.summary = dict(success=True)
|
|
|
|
ctx.summary['owner'] = ctx.owner
|
|
|
|
if ctx.description is not None:
|
|
ctx.summary['description'] = ctx.description
|
|
|
|
for task in ctx.config['tasks']:
|
|
msg = ('kernel installation shouldn be a base-level item, not part ' +
|
|
'of the tasks list')
|
|
assert 'kernel' not in task, msg
|
|
|
|
init_tasks = []
|
|
if ctx.lock:
|
|
msg = ('You cannot specify targets in a config file when using the ' +
|
|
'--lock option')
|
|
assert 'targets' not in ctx.config, msg
|
|
init_tasks.append({'internal.lock_machines': (
|
|
len(ctx.config['roles']), machine_type)})
|
|
|
|
init_tasks.extend([
|
|
{'internal.save_config': None},
|
|
{'internal.check_lock': None},
|
|
{'internal.connect': None},
|
|
{'internal.push_inventory': None},
|
|
{'internal.serialize_remote_roles': None},
|
|
{'internal.check_conflict': None},
|
|
])
|
|
if not ctx.config.get('use_existing_cluster', False):
|
|
init_tasks.extend([
|
|
{'internal.check_ceph_data': None},
|
|
{'internal.vm_setup': None},
|
|
])
|
|
if 'kernel' in ctx.config:
|
|
init_tasks.append({'kernel': ctx.config['kernel']})
|
|
init_tasks.extend([
|
|
{'internal.base': None},
|
|
{'internal.archive': None},
|
|
{'internal.coredump': None},
|
|
{'internal.sudo': None},
|
|
{'internal.syslog': None},
|
|
{'internal.timer': None},
|
|
])
|
|
|
|
ctx.config['tasks'][:0] = init_tasks
|
|
|
|
if ctx.suite_path is not None:
|
|
ctx.config['suite_path'] = ctx.suite_path
|
|
|
|
fetch_tasks_if_needed(ctx.config)
|
|
|
|
try:
|
|
run_tasks(tasks=ctx.config['tasks'], ctx=ctx)
|
|
finally:
|
|
if not ctx.summary.get('success') and bool(ctx.config.get('nuke-on-error')):
|
|
# only unlock if we locked them in the first place
|
|
nuke(ctx, ctx.lock)
|
|
if ctx.archive is not None:
|
|
with file(os.path.join(ctx.archive, 'summary.yaml'), 'w') as f:
|
|
yaml.safe_dump(ctx.summary, f, default_flow_style=False)
|
|
with contextlib.closing(StringIO.StringIO()) as f:
|
|
yaml.safe_dump(ctx.summary, f)
|
|
log.info('Summary data:\n%s' % f.getvalue())
|
|
with contextlib.closing(StringIO.StringIO()) as f:
|
|
if ('email-on-error' in ctx.config
|
|
and not ctx.summary.get('success', False)):
|
|
yaml.safe_dump(ctx.summary, f)
|
|
yaml.safe_dump(ctx.config, f)
|
|
emsg = f.getvalue()
|
|
subject = "Teuthology error -- %s" % ctx.summary[
|
|
'failure_reason']
|
|
email_results(subject, "Teuthology", ctx.config[
|
|
'email-on-error'], emsg)
|
|
|
|
report.try_push_job_info(ctx.config, ctx.summary)
|
|
|
|
if ctx.summary.get('success', True):
|
|
log.info('pass')
|
|
else:
|
|
log.info('FAIL')
|
|
sys.exit(1)
|