blob: e53b2abcfc707054647cf32a3f73ad0eea08957f [file] [log] [blame]
Matthew Hartfb6fd362020-03-04 21:03:59 +00001#!/usr/bin/env python3
2
3from __future__ import print_function
4
5__copyright__ = """
6/*
7 * Copyright (c) 2020, Arm Limited. All rights reserved.
8 *
9 * SPDX-License-Identifier: BSD-3-Clause
10 *
11 */
12 """
13
14"""
15Script for waiting for LAVA jobs and parsing the results
16"""
17
18import os
19import sys
20import shutil
21import time
22import yaml
23import argparse
24import threading
25from copy import deepcopy
26from collections import OrderedDict
27from jinja2 import Environment, FileSystemLoader
28from lava_helper_configs import *
29from lava_helper import test_lava_dispatch_credentials
30
31try:
32 from tfm_ci_pylib.utils import save_json, load_json, sort_dict,\
33 load_yaml, test, print_test
34 from tfm_ci_pylib.lava_rpc_connector import LAVA_RPC_connector
35except ImportError:
36 dir_path = os.path.dirname(os.path.realpath(__file__))
37 sys.path.append(os.path.join(dir_path, "../"))
38 from tfm_ci_pylib.utils import save_json, load_json, sort_dict,\
39 load_yaml, test, print_test
40 from tfm_ci_pylib.lava_rpc_connector import LAVA_RPC_connector
41
42def wait_for_jobs(user_args):
43 job_list = user_args.job_ids.split(",")
44 job_list = [int(x) for x in job_list if x != '']
45 lava = test_lava_dispatch_credentials(user_args)
46 finished_jobs = lava.block_wait_for_jobs(job_list, user_args.dispatch_timeout, 0.5)
47 unfinished_jobs = [item for item in job_list if item not in finished_jobs]
48 for job in unfinished_jobs:
49 info_print("Cancelling unfinished job: {}".format(job))
50 lava.cancel_job(job)
51 if user_args.artifacts_path:
52 for job, info in finished_jobs.items():
53 info['job_dir'] = os.path.join(user_args.artifacts_path, "{}_{}".format(str(job), info['description']))
54 finished_jobs[job] = info
55 finished_jobs = fetch_artifacts(finished_jobs, user_args, lava)
56 print_lava_urls(finished_jobs, user_args)
57 boot_report(finished_jobs, user_args)
58 test_report(finished_jobs, user_args, lava)
59
60def fetch_artifacts(jobs, user_args, lava):
61 if not user_args.artifacts_path:
62 return
63 for job_id, info in jobs.items():
64 job_dir = info['job_dir']
65 info_print("Fetching artifacts for JOB: {} to {}".format(job_id, job_dir))
66 os.makedirs(job_dir, exist_ok=True)
67 def_path = os.path.join(job_dir, 'definition.yaml')
68 target_log = os.path.join(job_dir, 'target_log.txt')
Matthew Hart4a4f1202020-06-12 15:52:46 +010069 config = os.path.join(job_dir, 'config.tar.bz2')
70 results_file = os.path.join(job_dir, 'results.yaml')
Matthew Hartfb6fd362020-03-04 21:03:59 +000071 definition, metadata = lava.get_job_definition(job_id, def_path)
72 jobs[job_id]['metadata'] = metadata
73 time.sleep(0.2) # be friendly to LAVA
Matthew Hart4a4f1202020-06-12 15:52:46 +010074 lava.get_job_log(job_id, target_log)
Matthew Hartfb6fd362020-03-04 21:03:59 +000075 time.sleep(0.2)
76 lava.get_job_config(job_id, config)
77 time.sleep(0.2)
Matthew Hart4a4f1202020-06-12 15:52:46 +010078 lava.get_job_results(job_id, results_file)
Matthew Hartfb6fd362020-03-04 21:03:59 +000079 return(jobs)
80
81
82def lava_id_to_url(id, user_args):
83 return "{}/scheduler/job/{}".format(user_args.lava_url, id)
84
85def boot_report(jobs, user_args):
86 incomplete_jobs = []
87 for job, info in jobs.items():
88 if info['health'] != 'Complete':
89 if info['error_reason'] == 'Infrastructure':
90 info_print("Job {} failed with Infrastructure error".format(job))
91 incomplete_jobs.append(job)
92 incomplete_output = [lava_id_to_url(x, user_args) for x in incomplete_jobs];
93 if len(incomplete_jobs) > 0:
94 print("BOOT_RESULT: -1 Failed: {}".format(incomplete_output))
95 else:
96 print("BOOT_RESULT: +1")
97
98def remove_lava_dupes(results):
99 for result in results:
100 if result['result'] != 'pass':
101 if result['suite'] == "lava":
102 for other in [x for x in results if x != result]:
103 if other['name'] == result['name']:
104 if other['result'] == 'pass':
105 results.remove(result)
106 return(results)
107
108def test_report(jobs, user_args, lava):
109 # parsing of test results is WIP
110 fail_j = []
111 jinja_data = []
112 for job, info in jobs.items():
Matthew Hart4a4f1202020-06-12 15:52:46 +0100113 results_file = os.path.join(info['job_dir'], 'results.yaml')
114 if not os.path.exists(results_file) or (os.path.getsize(results_file) == 0):
115 fail_j.append(job)
116 continue
117 with open(results_file, "r") as F:
118 res_data = F.read()
119 results = yaml.load(res_data)
Matthew Hartfb6fd362020-03-04 21:03:59 +0000120 non_lava_results = [x for x in results if x['suite'] != 'lava']
121 info['lava_url'] = lava_id_to_url(job, user_args)
122 info['artifacts_dir'] = "tf-m-ci-scripts/{}".format(info['job_dir'])
123 jinja_data.append({job: [info, non_lava_results]})
124 for result in non_lava_results:
125 if result['result'] != 'pass':
126 fail_j.append(job) if job not in fail_j else fail_j
127 time.sleep(0.5) # be friendly to LAVA
128 fail_output = [lava_id_to_url(x, user_args) for x in fail_j]
129 if len(fail_j) > 0:
130 print("TEST_RESULT: -1 Failed: {}".format(fail_output))
131 else:
132 print("TEST_RESULT: +1")
133 data = {}
134 data['jobs'] = jinja_data
135 render_jinja(data)
136
137def render_jinja(data):
138 work_dir = os.path.join(os.path.abspath(os.path.dirname(__file__)), "jinja2_templates")
139 template_loader = FileSystemLoader(searchpath=work_dir)
140 template_env = Environment(loader=template_loader)
141 html = template_env.get_template("test_summary.jinja2").render(data)
142 csv = template_env.get_template("test_summary_csv.jinja2").render(data)
143 with open('test_summary.html', "w") as F:
144 F.write(html)
145 with open('test_summary.csv', "w") as F:
146 F.write(csv)
147
148def print_lava_urls(jobs, user_args):
149 output = [lava_id_to_url(x, user_args) for x in jobs]
150 print("LAVA jobs triggered for this build: {}".format(output))
151
152
153def info_print(line):
154 print("INFO: {}".format(line))
155
156def main(user_args):
157 """ Main logic """
158 user_args.lava_rpc = "RPC2"
159 wait_for_jobs(user_args)
160
161def get_cmd_args():
162 """ Parse command line arguments """
163
164 # Parse command line arguments to override config
165 parser = argparse.ArgumentParser(description="Lava Wait Jobs")
166 cmdargs = parser.add_argument_group("Lava Wait Jobs")
167
168 # Configuration control
169 cmdargs.add_argument(
170 "--lava-url", dest="lava_url", action="store", help="LAVA lab URL (without RPC2)"
171 )
172 cmdargs.add_argument(
173 "--job-ids", dest="job_ids", action="store", required=True, help="Comma separated list of job IDS"
174 )
175 cmdargs.add_argument(
176 "--lava-token", dest="token_secret", action="store", help="LAVA auth token"
177 )
178 cmdargs.add_argument(
179 "--lava-user", dest="token_usr", action="store", help="LAVA username"
180 )
181 cmdargs.add_argument(
182 "--use-env", dest="token_from_env", action="store_true", default=False, help="Use LAVA auth info from environment"
183 )
184 cmdargs.add_argument(
185 "--lava-timeout", dest="dispatch_timeout", action="store", type=int, default=3600, help="Time in seconds to wait for all jobs"
186 )
187 cmdargs.add_argument(
188 "--artifacts-path", dest="artifacts_path", action="store", help="Download LAVA artifacts to this directory"
189 )
190 return parser.parse_args()
191
192
193if __name__ == "__main__":
194 main(get_cmd_args())