1
0
mirror of https://pagure.io/fedora-qa/createhdds.git synced 2024-11-22 07:13:09 +00:00

use openqa-python client instead of subprocess calling

Summary:
Since adamw created Python client for OpenQA, we
can use it instead of calling Perl in subprocess. It simplyfies
usage and special code for running in Docker is no longer needed.
This version requires user to create configuration file either
in `/etc/openqa/client.conf` or in `~/.config/openqa/client.conf`
with the same KEY and SECRET as in host machine.

To execute jobs in Docker, just specify correct server and
port (probably `[localhost:8080]`) in configuration file.

Only problem remains with self-signed certificate. It's
necessary to either disable SSL cert verifying, import
self-signed certificate or use HTTP instead of HTTPS in Docker,
see https://github.com/os-autoinst/openQA-python-client/pull/1.

Test Plan: Tested on running tests for compose F22 Final RC1.

Reviewers: adamwill, jskladan

Subscribers: tflink

Differential Revision: https://phab.qadevel.cloud.fedoraproject.org/D425
This commit is contained in:
Garret Raziel 2015-07-09 13:30:17 +02:00
parent 894e27ea84
commit 68c7c2a126
2 changed files with 47 additions and 61 deletions

View File

@ -1,11 +1,9 @@
#!/usr/bin/env python #!/usr/bin/env python
import json import json
import re
import urlgrabber import urlgrabber
import os.path import os.path
import sys import sys
import subprocess
import argparse import argparse
import datetime import datetime
import logging import logging
@ -16,13 +14,11 @@ except ImportError:
wikitcms = None wikitcms = None
import fedfind.release import fedfind.release
from openqa_client.client import OpenQA_Client
from report_job_results import report_results from report_job_results import report_results
PERSISTENT = "/var/tmp/openqa_watcher.json" PERSISTENT = "/var/tmp/openqa_watcher.json"
ISO_PATH = "/var/lib/openqa/factory/iso/" ISO_PATH = "/var/lib/openqa/factory/iso/"
RUN_COMMAND = "/var/lib/openqa/script/client isos post " \
"ISO=%s DISTRI=fedora VERSION=rawhide FLAVOR=%s ARCH=%s BUILD=%s"
DOCKER_COMMAND = "docker exec %s " + RUN_COMMAND
ARCHES = ['i386', 'x86_64'] ARCHES = ['i386', 'x86_64']
@ -69,46 +65,35 @@ def download_image(image):
return isoname return isoname
def run_openqa_jobs(isoname, flavor, arch, build, docker_container): def run_openqa_jobs(client, isoname, flavor, arch, build):
"""# run OpenQA 'isos' job on selected isoname, with given arch """# run OpenQA 'isos' job on selected isoname, with given arch
and a version string. If provided, use docker container docker_container and a version string. **NOTE**: the version passed to OpenQA as
that includes OpenQA WebUI. **NOTE**: the version passed to OpenQA as
BUILD and is parsed back into the 'relval report-auto' arguments BUILD and is parsed back into the 'relval report-auto' arguments
by report_job_results.py; it is expected to be in the form of a by report_job_results.py; it is expected to be in the form of a
3-tuple on which join('_') has been run, and the three elements 3-tuple on which join('_') has been run, and the three elements
will be passed as --release, --compose and --milestone. Returns will be passed as --release, --compose and --milestone. Returns
list of job IDs. list of job IDs.
""" """
if docker_container: logging.info("sending jobs on OpenQA")
command = DOCKER_COMMAND % (docker_container, isoname, flavor, arch, build)
else:
command = RUN_COMMAND % (isoname, flavor, arch, build)
logging.info("executing: %s", command)
# starts OpenQA jobs # starts OpenQA jobs
output = subprocess.check_output(command.split()) params = {
'ISO': isoname,
'DISTRI': 'fedora',
'VERSION': 'rawhide', # TODO
'FLAVOR': flavor,
'ARCH': arch,
'BUILD': build
}
output = client.openqa_request('POST', 'isos', params)
logging.debug("command executed") logging.debug("executed")
logging.info("planned jobs: %s", output["ids"])
# read ids from OpenQA to wait for return output["ids"]
r = re.compile(r'ids => \[(?P<from>\d+)( \.\. (?P<to>\d+))?\]')
match = r.search(output)
if match and match.group('to'):
from_i = int(match.group('from'))
to_i = int(match.group('to')) + 1
logging.info("planned jobs: %d to %d", from_i, to_i - 1)
return range(from_i, to_i)
elif match:
job_id = int(match.group('from'))
logging.info("planned job: %d", job_id)
return [job_id]
else:
logging.info("no planned jobs")
return []
def jobs_from_current(wiki, docker_container): def jobs_from_current(wiki, client):
"""Schedule jobs against the 'current' release validation event """Schedule jobs against the 'current' release validation event
(according to wikitcms) if we have not already. Returns a tuple, (according to wikitcms) if we have not already. Returns a tuple,
first value is the job list, second is the current event. first value is the job list, second is the current event.
@ -133,7 +118,7 @@ def jobs_from_current(wiki, docker_container):
jobs = [] jobs = []
try: try:
jobs = jobs_from_fedfind(currev.ff_release, runarches, docker_container) jobs = jobs_from_fedfind(currev.ff_release, client, runarches)
logging.info("planned jobs: %s", jobs) logging.info("planned jobs: %s", jobs)
# write info about latest versions # write info about latest versions
@ -147,7 +132,7 @@ def jobs_from_current(wiki, docker_container):
return (jobs, currev) return (jobs, currev)
def jobs_from_fedfind(ff_release, arches=ARCHES, docker_container=None): def jobs_from_fedfind(ff_release, client, arches=ARCHES):
"""Given a fedfind.Release object, find the ISOs we want and run """Given a fedfind.Release object, find the ISOs we want and run
jobs on them. arches is an iterable of arches to run on, if not jobs on them. arches is an iterable of arches to run on, if not
specified, we'll use our constant. specified, we'll use our constant.
@ -203,14 +188,14 @@ def jobs_from_fedfind(ff_release, arches=ARCHES, docker_container=None):
continue continue
logging.info("running universal tests for %s with %s", arch, bestimg.desc) logging.info("running universal tests for %s with %s", arch, bestimg.desc)
isoname = download_image(bestimg) isoname = download_image(bestimg)
job_ids = run_openqa_jobs(isoname, 'universal', arch, build, docker_container) job_ids = run_openqa_jobs(client, isoname, 'universal', arch, build)
jobs.extend(job_ids) jobs.extend(job_ids)
# Now schedule per-image jobs. # Now schedule per-image jobs.
for image in images: for image in images:
isoname = download_image(image) isoname = download_image(image)
flavor = '_'.join((image.payload, image.imagetype)) flavor = '_'.join((image.payload, image.imagetype))
job_ids = run_openqa_jobs(isoname, flavor, image.arch, build, docker_container) job_ids = run_openqa_jobs(client, isoname, flavor, image.arch, build)
jobs.extend(job_ids) jobs.extend(job_ids)
return jobs return jobs
@ -218,21 +203,21 @@ def jobs_from_fedfind(ff_release, arches=ARCHES, docker_container=None):
# SUB-COMMAND FUNCTIONS # SUB-COMMAND FUNCTIONS
def run_current(args, wiki): def run_current(args, client, wiki):
"""run OpenQA for current release validation event, if we have """run OpenQA for current release validation event, if we have
not already done it. not already done it.
""" """
logging.info("running on current release") logging.info("running on current release")
jobs, _ = jobs_from_current(wiki, args.docker_container) jobs, _ = jobs_from_current(wiki, client)
# wait for jobs to finish and display results # wait for jobs to finish and display results
if jobs: if jobs:
logging.info("waiting for jobs: %s", jobs) logging.info("waiting for jobs: %s", jobs)
report_results(jobs) report_results(jobs, client)
logging.debug("finished") logging.debug("finished")
sys.exit() sys.exit()
def run_compose(args, wiki=None): def run_compose(args, client, wiki=None):
"""run OpenQA on a specified compose, optionally reporting results """run OpenQA on a specified compose, optionally reporting results
if a matching wikitcms ValidationEvent is found by relval/wikitcms if a matching wikitcms ValidationEvent is found by relval/wikitcms
""" """
@ -251,19 +236,19 @@ def run_compose(args, wiki=None):
jobs = [] jobs = []
try: try:
if args.arch: if args.arch:
jobs = jobs_from_fedfind(ff_release, [args.arch], args.docker_container) jobs = jobs_from_fedfind(ff_release, client, [args.arch])
else: else:
jobs = jobs_from_fedfind(ff_release, docker_container=args.docker_container) jobs = jobs_from_fedfind(ff_release, client)
except TriggerException as e: except TriggerException as e:
logging.error("cannot run jobs: %s", e) logging.error("cannot run jobs: %s", e)
logging.info("planned jobs: %s", jobs) logging.info("planned jobs: %s", jobs)
if args.submit_results: if args.submit_results:
report_results(jobs) report_results(jobs, client)
logging.debug("finished") logging.debug("finished")
sys.exit() sys.exit()
def run_all(args, wiki=None): def run_all(args, client, wiki=None):
"""Do everything we can: test current validation event compose if """Do everything we can: test current validation event compose if
it's new, amd test both Rawhide and Branched nightlies if they it's new, amd test both Rawhide and Branched nightlies if they
exist and aren't the same as the 'current' compose. exist and aren't the same as the 'current' compose.
@ -273,7 +258,7 @@ def run_all(args, wiki=None):
# Run for 'current' validation event. # Run for 'current' validation event.
logging.debug("running for current") logging.debug("running for current")
(jobs, currev) = jobs_from_current(wiki, args.docker_container) (jobs, currev) = jobs_from_current(wiki, client)
logging.info("jobs from current validation event: %s", jobs) logging.info("jobs from current validation event: %s", jobs)
utcdate = datetime.datetime.utcnow() utcdate = datetime.datetime.utcnow()
@ -290,7 +275,7 @@ def run_all(args, wiki=None):
try: try:
logging.debug("running for rawhide") logging.debug("running for rawhide")
rawhide_ffrel = fedfind.release.get_release(release='Rawhide', compose=utcdate) rawhide_ffrel = fedfind.release.get_release(release='Rawhide', compose=utcdate)
rawjobs = jobs_from_fedfind(rawhide_ffrel, docker_container=args.docker_container) rawjobs = jobs_from_fedfind(rawhide_ffrel, client)
logging.info("jobs from rawhide %s: %s", rawhide_ffrel.version, rawjobs) logging.info("jobs from rawhide %s: %s", rawhide_ffrel.version, rawjobs)
jobs.extend(rawjobs) jobs.extend(rawjobs)
except ValueError as err: except ValueError as err:
@ -307,7 +292,7 @@ def run_all(args, wiki=None):
logging.debug("running for branched") logging.debug("running for branched")
branched_ffrel = fedfind.release.get_release(release=currev.release, branched_ffrel = fedfind.release.get_release(release=currev.release,
milestone='Branched', compose=utcdate) milestone='Branched', compose=utcdate)
branchjobs = jobs_from_fedfind(branched_ffrel, docker_container=args.docker_container) branchjobs = jobs_from_fedfind(branched_ffrel, client)
logging.info("jobs from %s: %s", branched_ffrel.version, branchjobs) logging.info("jobs from %s: %s", branched_ffrel.version, branchjobs)
jobs.extend(branchjobs) jobs.extend(branchjobs)
except ValueError as err: except ValueError as err:
@ -316,7 +301,7 @@ def run_all(args, wiki=None):
logging.error("cannot run jobs: %s", e) logging.error("cannot run jobs: %s", e)
if jobs: if jobs:
logging.info("waiting for jobs: %s", jobs) logging.info("waiting for jobs: %s", jobs)
report_results(jobs) report_results(jobs, client)
logging.debug("finished") logging.debug("finished")
sys.exit() sys.exit()
@ -366,9 +351,6 @@ if __name__ == "__main__":
required=False, action='store_true') required=False, action='store_true')
parser_all.set_defaults(func=run_all) parser_all.set_defaults(func=run_all)
parser.add_argument(
'-d', '--docker-container', help="If given, run tests using "
"specified docker container")
parser.add_argument( parser.add_argument(
'-t', '--test', help=test_help, required=False, action='store_true') '-t', '--test', help=test_help, required=False, action='store_true')
parser.add_argument( parser.add_argument(
@ -408,4 +390,7 @@ if __name__ == "__main__":
wiki = wikitcms.wiki.Wiki(('https', 'fedoraproject.org'), '/w/') wiki = wikitcms.wiki.Wiki(('https', 'fedoraproject.org'), '/w/')
else: else:
logging.warn("wikitcms not found, reporting to wiki disabled") logging.warn("wikitcms not found, reporting to wiki disabled")
args.func(args, wiki)
client = OpenQA_Client() # uses first server from ~/.config/openqa/client.conf
args.func(args, client, wiki)

View File

@ -1,4 +1,3 @@
import requests
import argparse import argparse
import sys import sys
import time import time
@ -6,25 +5,26 @@ import logging
import conf_test_suites import conf_test_suites
from operator import attrgetter from operator import attrgetter
from openqa_client.client import OpenQA_Client
from wikitcms.wiki import Wiki, ResTuple from wikitcms.wiki import Wiki, ResTuple
API_ROOT = "http://localhost/api/v1"
SLEEPTIME = 60 SLEEPTIME = 60
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
def get_passed_testcases(job_ids): def get_passed_testcases(job_ids, client):
""" """
job_ids ~ list of int (job ids) job_ids ~ list of int (job ids)
Returns ~ list of str - names of passed testcases Returns ~ list of str - names of passed testcases
""" """
running_jobs = dict([(job_id, "%s/jobs/%s" % (API_ROOT, job_id)) for job_id in job_ids]) running_jobs = dict([(job_id, "jobs/%s" % job_id) for job_id in job_ids])
logger.info("running jobs: %s", running_jobs) logger.info("running jobs: %s", running_jobs)
finished_jobs = {} finished_jobs = {}
while running_jobs: while running_jobs:
for job_id, url in running_jobs.items(): for job_id, url in running_jobs.items():
job_state = requests.get(url).json()['job'] output = client.openqa_request('GET', url)
job_state = output['job']
if job_state['state'] == 'done': if job_state['state'] == 'done':
logger.info("job %s is done", job_id) logger.info("job %s is done", job_id)
finished_jobs[job_id] = job_state finished_jobs[job_id] = job_state
@ -36,7 +36,7 @@ def get_passed_testcases(job_ids):
passed_testcases = set() passed_testcases = set()
for job_id in job_ids: for job_id in job_ids:
job = finished_jobs[job_id] job = finished_jobs[job_id]
if job['result'] =='passed': if job['result'] == 'passed':
(release, milestone, compose) = job['settings']['BUILD'].split('_') (release, milestone, compose) = job['settings']['BUILD'].split('_')
testsuite = job['settings']['TEST'] testsuite = job['settings']['TEST']
arch = job['settings']['ARCH'] arch = job['settings']['ARCH']
@ -60,8 +60,8 @@ def get_passed_testcases(job_ids):
return sorted(list(passed_testcases), key=attrgetter('testcase')) return sorted(list(passed_testcases), key=attrgetter('testcase'))
def report_results(job_ids, verbose=False, report=True): def report_results(job_ids, client, verbose=False, report=True):
passed_testcases = get_passed_testcases(job_ids) passed_testcases = get_passed_testcases(job_ids, client)
if verbose: if verbose:
for restup in passed_testcases: for restup in passed_testcases:
print restup print restup
@ -96,4 +96,5 @@ if __name__ == "__main__":
parser.add_argument('--report', default=False, action='store_true') parser.add_argument('--report', default=False, action='store_true')
args = parser.parse_args() args = parser.parse_args()
report_results(args.jobs, verbose=True, report=args.report) client = OpenQA_Client() # uses first server from ~/.config/openqa/client.conf
report_results(args.jobs, client, verbose=True, report=args.report)