mirror of
https://github.com/ceph/ceph
synced 2024-12-14 07:25:50 +00:00
cfd5456f3f
suite = many collections, and maybe some shared files collection = a collection of facets facet = a config fragment
162 lines
4.7 KiB
Python
162 lines
4.7 KiB
Python
import argparse
|
|
import errno
|
|
import itertools
|
|
import logging
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="""
|
|
Run a suite of ceph integration tests.
|
|
|
|
A suite is a directory containing a subdirectory collections/
|
|
containing collections.
|
|
|
|
A collection is a directory containing facets.
|
|
|
|
A facet is a directory containing config snippets.
|
|
|
|
Running the suite means running teuthology for every collection.
|
|
|
|
Running a collection means running teuthology for every configuration
|
|
combination generated by taking one config snippet from each facet.
|
|
|
|
Any config files passed on the command line will be used for every
|
|
combination, and will override anything in the suite.
|
|
""")
|
|
parser.add_argument(
|
|
'-v', '--verbose',
|
|
action='store_true', default=None,
|
|
help='be more verbose',
|
|
)
|
|
parser.add_argument(
|
|
'--suite',
|
|
metavar='DIR',
|
|
help='suite of tests to run',
|
|
required=True,
|
|
)
|
|
parser.add_argument(
|
|
'--owner',
|
|
help='job owner',
|
|
)
|
|
parser.add_argument(
|
|
'--name',
|
|
help='name for this suite',
|
|
required=True,
|
|
)
|
|
parser.add_argument(
|
|
'config',
|
|
metavar='CONFFILE',
|
|
nargs='*',
|
|
default=[],
|
|
help='config file to read',
|
|
)
|
|
|
|
args = parser.parse_args()
|
|
|
|
loglevel = logging.INFO
|
|
if args.verbose:
|
|
loglevel = logging.DEBUG
|
|
|
|
logging.basicConfig(
|
|
level=loglevel,
|
|
)
|
|
|
|
collection_dir = os.path.join(args.suite,'collections')
|
|
print collection_dir
|
|
if os.path.exists(collection_dir) and os.path.isdir(collection_dir):
|
|
collections = [
|
|
(os.path.join(collection_dir, f), f)
|
|
for f in sorted(os.listdir(collection_dir))
|
|
if not f.startswith('.')
|
|
and os.path.isdir(os.path.join(collection_dir, f))
|
|
]
|
|
else:
|
|
# degenerate case; 'suite' is actually a single collection
|
|
collections = [(args.suite, 'none')]
|
|
|
|
for collection, collection_name in sorted(collections):
|
|
log.info('Collection %s in %s' % (collection_name, collection))
|
|
facets = [
|
|
f for f in sorted(os.listdir(collection))
|
|
if not f.startswith('.')
|
|
and os.path.isdir(os.path.join(collection, f))
|
|
]
|
|
facet_configs = (
|
|
[(f, name, os.path.join(collection, f, name))
|
|
for name in sorted(os.listdir(os.path.join(collection, f)))
|
|
if not name.startswith('.')
|
|
and name.endswith('.yaml')
|
|
]
|
|
for f in facets
|
|
)
|
|
for configs in itertools.product(*facet_configs):
|
|
description = 'collection:%s ' % (collection_name);
|
|
description += ' '.join('{facet}:{name}'.format(
|
|
facet=facet, name=name)
|
|
for facet, name, path in configs)
|
|
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.extend([
|
|
'--name', args.name,
|
|
'--description', description,
|
|
'--',
|
|
])
|
|
|
|
arg.extend(path for facet, name, path in configs)
|
|
arg.extend(args.config)
|
|
print arg
|
|
subprocess.check_call(
|
|
args=arg,
|
|
)
|
|
|
|
def ls():
|
|
parser = argparse.ArgumentParser(description='List teuthology job results')
|
|
parser.add_argument(
|
|
'--archive-dir',
|
|
metavar='DIR',
|
|
help='path under which to archive results',
|
|
required=True,
|
|
)
|
|
args = parser.parse_args()
|
|
|
|
import yaml
|
|
|
|
for j in sorted(os.listdir(args.archive_dir)):
|
|
if j.startswith('.'):
|
|
continue
|
|
|
|
summary = {}
|
|
try:
|
|
with file('%s/%s/summary.yaml' % (args.archive_dir, j)) as f:
|
|
g = yaml.safe_load_all(f)
|
|
for new in g:
|
|
summary.update(new)
|
|
except IOError, e:
|
|
if e.errno == errno.ENOENT:
|
|
print "%s (no summary.yaml)" % j
|
|
continue
|
|
else:
|
|
raise
|
|
|
|
print "{job} {success} {owner} {desc}".format(
|
|
job=j,
|
|
owner=summary.get('owner', '-'),
|
|
desc=summary.get('description', '-'),
|
|
success='pass' if summary['success'] else 'FAIL',
|
|
)
|