From 55d5d1b4ce4bfd7ae7c239c8aca03bceee2f1f06 Mon Sep 17 00:00:00 2001
From: Adam Williamson <awilliam@redhat.com>
Date: Thu, 12 Feb 2015 19:32:27 -0800
Subject: [PATCH 1/3] use python-wikitcms and fedfind to handle events and
 images

This removes a bunch of template-y bits that fedfind does
better, and should make things work for all validation events.
The CLI for openqa_trigger is completely redone to use
argparse and check values and stuff. The syntax for the event
sub-command is purposely similar to relval report-auto. Note
this requires wikitcms changes currently in git master.
---
 tools/openqa_trigger/openqa_trigger.py     | 159 +++++++++++++++++++----------
 tools/openqa_trigger/report_job_results.py |   7 +-
 2 files changed, 108 insertions(+), 58 deletions(-)

diff --git a/tools/openqa_trigger/openqa_trigger.py b/tools/openqa_trigger/openqa_trigger.py
index 9406d0c..7424c8b 100755
--- a/tools/openqa_trigger/openqa_trigger.py
+++ b/tools/openqa_trigger/openqa_trigger.py
@@ -7,15 +7,15 @@ import urlgrabber
 import os.path
 import sys
 import subprocess
+import argparse
+import wikitcms.wiki
+import fedfind.release
 
 from report_job_results import report_results
 
 PERSISTENT = "/var/tmp/openqa_watcher.json"
-CURRENT_TEST = "https://fedoraproject.org/wiki/Test_Results:Current_Installation_Test"
-ISO_URL = "https://kojipkgs.fedoraproject.org/mash/rawhide-%s/rawhide/%s/os/images/boot.iso"
-ISO_REGEX = re.compile(r'https://kojipkgs\.fedoraproject\.org/mash/(?P<name>rawhide-(?P<build>\d+))/rawhide/(?P<arch>x86_64|i386)/os/images/boot\.iso')
 ISO_PATH = "/var/lib/openqa/factory/iso/"
-RUN_COMMAND = "/var/lib/openqa/script/client isos post ISO=%s DISTRI=fedora VERSION=rawhide FLAVOR=server ARCH=%s BUILD=%s_%s"
+RUN_COMMAND = "/var/lib/openqa/script/client isos post ISO=%s DISTRI=fedora VERSION=rawhide FLAVOR=server ARCH=%s BUILD=%s"
 VERSIONS = ['i386', 'x86_64']
 
 # read last tested version from file
@@ -33,27 +33,27 @@ def read_last():
         result[version] = json_parsed.get(version, None)
     return result, json_parsed
 
-# read current version from Current Installation Test page
-def read_currents():
-    page = urllib2.urlopen(CURRENT_TEST).read()
-    f_regex = re.compile(r'<title>.*Fedora (?P<version>\d+).*</title>')
-    m = f_regex.search(page)
-    for match in ISO_REGEX.finditer(page):
-        yield m.group('version'), match.group("build"), match.group(0), match.group("name"), match.group("arch")
-
-# download rawhide iso from koji
-def download_rawhide_iso(link, name, arch):
-    isoname = "%s_%s.iso" % (name, arch)
+def download_image(image, event):
+    """Download a given image with a name that should be unique for
+    this event and arch (until we start testing different images
+    for the same event and arch). Returns the filename of the image
+    (not the path).
+    """
+    isoname = "{0}_{1}.iso".format(event.version.replace(' ', '_'), image.arch)
     filename = os.path.join(ISO_PATH, isoname)
     if not os.path.isfile(filename):
-        link = "http://" + link[len("https://"):]
-        urlgrabber.urlgrab(link, filename)
+        # Icky hack around a urlgrabber bug:
+        # https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=715416
+        urlgrabber.urlgrab(image.url.replace('https', 'http'), filename)
     return isoname
 
-# run OpenQA 'isos' job on selected isoname, with given arch and build
-# returns list of job IDs
-def run_openqa_jobs(isoname, arch, fedora_version, build):
-    command = RUN_COMMAND % (isoname, arch, fedora_version, build)
+def run_openqa_jobs(isoname, arch, event_version):
+    """# run OpenQA 'isos' job on selected isoname, with given arch
+    and event version as the 'build'. **NOTE**: the 'build' is parsed
+    back into the 'relval report-auto' arguments later. Using
+    event.version makes sure this works. Returns list of job IDs
+    """
+    command = RUN_COMMAND % (isoname, arch, event_version.replace(' ', '_'))
 
     # starts OpenQA jobs
     output = subprocess.check_output(command.split())
@@ -70,28 +70,20 @@ def run_openqa_jobs(isoname, arch, fedora_version, build):
     else:
         return []
 
-# run OpenQA on rawhide if there is newer version since last run
-def run_if_newer():
+# run OpenQA on current compose if it is newer version since last run
+def run_current(args, wiki):
     last_versions, json_parsed = read_last()
-    jobs = []
-
-    # for every architecture
-    for f_version, current_version, link, name, arch in read_currents():
-        # don't run when there is newer version
+    currev = wiki.current_event
+    print("Current event: {0}".format(currev.version))
+    runarches = []
+    for arch in VERSIONS:
         last_version = last_versions.get(arch, None)
-        print f_version, current_version, link, name, arch,
-        if last_version is not None and (last_version >= current_version):
-            print " - Skipped"
-            continue
-
-        print ""
-
-        json_parsed[arch] = current_version
-
-        isoname = download_rawhide_iso(link, name, arch)
-        job_ids = run_openqa_jobs(isoname, arch, f_version, current_version)
-
-        jobs.extend(job_ids)
+        if last_version and last_version >= currev.sortname:
+            print("Skipped: {0}".format(arch))
+        else:
+            runarches.append(arch)
+            json_parsed[arch] = currev.sortname
+    jobs = jobs_from_event(currev, runarches)
 
     # write info about latest versions
     f = open(PERSISTENT, "w")
@@ -101,18 +93,81 @@ def run_if_newer():
     # wait for jobs to finish and display results
     print jobs
     report_results(jobs)
+    sys.exit()
 
+# run OpenQA on a specified event (don't update 'current' records
+# or report results)
+def run_event(args, wiki):
+    try:
+        event = wiki.get_validation_event(
+            args.release, args.build, args.version)
+    except ValueError as err:
+        sys.exit(err[0])
+    if args.arch:
+        print(jobs_from_event(event, [args.arch]))
+    else:
+        print(jobs_from_event(event))
+    sys.exit()
+
+def jobs_from_event(event, arches=VERSIONS):
+    """Given a python-wikitcms ValidationEvent, find the ISOs we want
+    and run jobs on them. arches is an iterable of arches to run on,
+    if not specified, we'll use our constant."""
+    # Find boot.iso images for our arches; third query is a bit of a
+    # bodge till I know what 22 TCs/RCs will actually look like,
+    # ideally we want a query that will reliably return one image per
+    # arch without us having to filter further, but we can always just
+    # take the first image for each arch if necessary
+    jobs = []
+    queries = (
+        fedfind.release.Query('imagetype', ('boot',)),
+        fedfind.release.Query('arch', arches),
+        fedfind.release.Query('payload', ('server', 'generic')))
+
+    for image in event.ff_release.find_images(queries):
+        print("{0} {1}".format(image.url, image.desc))
+        isoname = download_image(image, event)
+        job_ids = run_openqa_jobs(isoname, image.arch, event.version)
+        jobs.extend(job_ids)
+    return jobs
 
 if __name__ == "__main__":
-    if len(sys.argv) == 1:
-        run_if_newer()
-    elif len(sys.argv) == 3:
-        version = sys.argv[1]
-        arch = sys.argv[2]
-        name = "rawhide-%s" % version
-        link = ISO_URL % (sys.argv[1], sys.argv[2])
-        isoname = download_rawhide_iso(link, name, arch)
-        job_ids = run_openqa_jobs(isoname, arch, "", version)
-        print job_ids
+    test_help = "Operate on the staging wiki (for testing)"
+    parser = argparse.ArgumentParser(description=(
+        "Run OpenQA tests for a release validation test event."))
+    subparsers = parser.add_subparsers()
+
+    parser_current = subparsers.add_parser(
+        'current', description="Run for the current event, if needed.")
+    parser_current.add_argument(
+        '-t', '--test', help=test_help, required=False, action='store_true')
+    parser_current.set_defaults(func=run_current)
+
+    parser_event = subparsers.add_parser(
+        'event', description="Run for a specific event.")
+    parser_event.add_argument(
+        '-r', '--release', type=int, required=True, choices=range(12, 100),
+        metavar="12-99", help="Release number of a specific compose to run "
+        "against.")
+    parser_event.add_argument(
+        '-b', '--build', help="The build to run for; either a milestone "
+        "(for a TC/RC), or 'Rawhide' or 'Branched' (for a nightly build)",
+        required=True,
+        choices=['Alpha', 'Beta', 'Final', 'Branched', 'Rawhide'])
+    parser_event.add_argument(
+        '-v', '--version', help="The version to run for; either the compose "
+        "(for a TC/RC), or the date (for a nightly build)", required=True,
+        metavar="{T,R}C1-19 or YYYYMMDD")
+    parser_event.add_argument(
+        '-a', '--arch', help="The arch to run for", required=False,
+        choices=('x86_64', 'i386'))
+    parser_event.add_argument(
+        '-t', '--test', help=test_help, required=False, action='store_true')
+    parser_event.set_defaults(func=run_event)
+
+    args = parser.parse_args()
+    if args.test:
+        wiki = wikitcms.wiki.Wiki(('https', 'stg.fedoraproject.org'), '/w/')
     else:
-        print "%s [rawhide_version arch]" % sys.arv[0]
+        wiki = wikitcms.wiki.Wiki(('https', 'fedoraproject.org'), '/w/')
+    args.func(args, wiki)
diff --git a/tools/openqa_trigger/report_job_results.py b/tools/openqa_trigger/report_job_results.py
index 31436a6..a617562 100644
--- a/tools/openqa_trigger/report_job_results.py
+++ b/tools/openqa_trigger/report_job_results.py
@@ -46,12 +46,7 @@ def get_relval_commands(passed_testcases):
     for key in passed_testcases:
         cmd_ = relval_template
         version, _, build, arch = key
-
-        if version == 'rawhide':
-            cmd_ += ' --release "%s" --build Rawhide --version "%s"' % tuple(build.split('_')) #"22_20150110"
-        elif version == 'branched':
-            #cmd_ += ' --release "%s" --milestone "%s" --compose "%s"' % tuple(build.split('_')) #"22_Alpha_TC1"
-            continue
+        cmd_ += ' --release "%s" --build %s --version "%s"' % tuple(build.split('_'))
 
         for tc_name in passed_testcases[key]:
             testcase = conf_test_suites.TESTCASES[tc_name]
-- 
2.3.0

