blob: abd9c8a1531db04dbcd52e3758c957bbfc8b8b7d [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/*
Xinyu Zhang78c146a2022-09-05 19:06:40 +08007 * Copyright (c) 2020-2022, Arm Limited. All rights reserved.
Matthew Hartfb6fd362020-03-04 21:03:59 +00008 *
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
Matthew Hartfb6fd362020-03-04 21:03:59 +000019import time
20import yaml
21import argparse
Xinyu Zhangc8a670c2021-05-18 20:20:53 +080022import shutil
Matthew Hartfb6fd362020-03-04 21:03:59 +000023from jinja2 import Environment, FileSystemLoader
Matthew Hartfb6fd362020-03-04 21:03:59 +000024from lava_helper import test_lava_dispatch_credentials
Xinyu Zhangc918b6e2022-10-08 17:13:17 +080025from lava_submit_jobs import submit_lava_jobs
Paul Sokolovsky2512ec52022-03-04 00:15:39 +030026import codecov_helper
27
Matthew Hartfb6fd362020-03-04 21:03:59 +000028
Matthew Hartfb6fd362020-03-04 21:03:59 +000029def wait_for_jobs(user_args):
30 job_list = user_args.job_ids.split(",")
31 job_list = [int(x) for x in job_list if x != '']
32 lava = test_lava_dispatch_credentials(user_args)
Xinyu Zhangf2b7cbf2021-05-18 20:17:34 +080033 finished_jobs = get_finished_jobs(job_list, user_args, lava)
Xinyu Zhangc8a670c2021-05-18 20:20:53 +080034 resubmit_jobs = resubmit_failed_jobs(finished_jobs, user_args)
Paul Sokolovskyc87beee2022-04-30 08:50:47 +030035 if resubmit_jobs:
36 info_print("Waiting for resubmitted jobs: {}".format(resubmit_jobs))
37 finished_resubmit_jobs = get_finished_jobs(resubmit_jobs, user_args, lava)
38 finished_jobs.update(finished_resubmit_jobs)
Paul Sokolovsky451f67b2022-03-08 19:44:41 +030039 return finished_jobs
40
Paul Sokolovsky451f67b2022-03-08 19:44:41 +030041def process_finished_jobs(finished_jobs, user_args):
Xinyu Zhangf2b7cbf2021-05-18 20:17:34 +080042 print_lava_urls(finished_jobs, user_args)
Paul Sokolovsky451f67b2022-03-08 19:44:41 +030043 test_report(finished_jobs, user_args)
Xinyu Zhangf2b7cbf2021-05-18 20:17:34 +080044 failure_report(finished_jobs, user_args)
Xinyu Zhang82dab282022-10-09 16:33:19 +080045 job_links(finished_jobs, user_args)
Xinyu Zhangf2b7cbf2021-05-18 20:17:34 +080046 csv_report(finished_jobs)
Paul Sokolovsky2512ec52022-03-04 00:15:39 +030047 codecov_helper.coverage_reports(finished_jobs, user_args)
Xinyu Zhangf2b7cbf2021-05-18 20:17:34 +080048
49def get_finished_jobs(job_list, user_args, lava):
Paul Sokolovsky697f9552022-05-05 10:44:27 +030050 finished_jobs = lava.block_wait_for_jobs(job_list, user_args.dispatch_timeout, 5)
Matthew Hartfb6fd362020-03-04 21:03:59 +000051 unfinished_jobs = [item for item in job_list if item not in finished_jobs]
52 for job in unfinished_jobs:
53 info_print("Cancelling unfinished job: {}".format(job))
54 lava.cancel_job(job)
55 if user_args.artifacts_path:
56 for job, info in finished_jobs.items():
57 info['job_dir'] = os.path.join(user_args.artifacts_path, "{}_{}".format(str(job), info['description']))
58 finished_jobs[job] = info
59 finished_jobs = fetch_artifacts(finished_jobs, user_args, lava)
Xinyu Zhangf2b7cbf2021-05-18 20:17:34 +080060 return finished_jobs
Matthew Hartfb6fd362020-03-04 21:03:59 +000061
Xinyu Zhangc8a670c2021-05-18 20:20:53 +080062def resubmit_failed_jobs(jobs, user_args):
63 if not jobs:
64 return []
Xinyu Zhang4aca6d02021-05-31 11:43:32 +080065 time.sleep(2) # be friendly to LAVA
Xinyu Zhangc8a670c2021-05-18 20:20:53 +080066 failed_job = []
67 os.makedirs('failed_jobs', exist_ok=True)
68 for job_id, info in jobs.items():
69 if not (info['health'] == "Complete" and info['state'] == "Finished"):
70 job_dir = info['job_dir']
71 def_path = os.path.join(job_dir, 'definition.yaml')
72 os.rename(def_path, 'failed_jobs/{}_definition.yaml'.format(job_id))
73 shutil.rmtree(job_dir)
74 failed_job.append(job_id)
75 for failed_job_id in failed_job:
76 jobs.pop(failed_job_id)
Xinyu Zhangc918b6e2022-10-08 17:13:17 +080077 resubmitted_jobs = submit_lava_jobs(user_args, job_dir='failed_jobs')
Xinyu Zhangc8a670c2021-05-18 20:20:53 +080078 resubmitted_jobs = [int(x) for x in resubmitted_jobs if x != '']
79 return resubmitted_jobs
80
Matthew Hartfb6fd362020-03-04 21:03:59 +000081def fetch_artifacts(jobs, user_args, lava):
82 if not user_args.artifacts_path:
83 return
84 for job_id, info in jobs.items():
85 job_dir = info['job_dir']
86 info_print("Fetching artifacts for JOB: {} to {}".format(job_id, job_dir))
87 os.makedirs(job_dir, exist_ok=True)
88 def_path = os.path.join(job_dir, 'definition.yaml')
89 target_log = os.path.join(job_dir, 'target_log.txt')
Matthew Hart4a4f1202020-06-12 15:52:46 +010090 config = os.path.join(job_dir, 'config.tar.bz2')
91 results_file = os.path.join(job_dir, 'results.yaml')
Xinyu Zhang82dab282022-10-09 16:33:19 +080092 definition = lava.get_job_definition(job_id, def_path)
93 jobs[job_id]['metadata'] = definition.get('metadata', [])
Matthew Hartfb6fd362020-03-04 21:03:59 +000094 time.sleep(0.2) # be friendly to LAVA
Matthew Hart4a4f1202020-06-12 15:52:46 +010095 lava.get_job_log(job_id, target_log)
Matthew Hartfb6fd362020-03-04 21:03:59 +000096 time.sleep(0.2)
97 lava.get_job_config(job_id, config)
98 time.sleep(0.2)
Matthew Hart4a4f1202020-06-12 15:52:46 +010099 lava.get_job_results(job_id, results_file)
Paul Sokolovskyc2d6d882022-02-25 19:11:18 +0300100 codecov_helper.extract_trace_data(target_log, job_dir)
Matthew Hartfb6fd362020-03-04 21:03:59 +0000101 return(jobs)
102
103
104def lava_id_to_url(id, user_args):
105 return "{}/scheduler/job/{}".format(user_args.lava_url, id)
106
Xinyu Zhang1b8f5152020-11-13 16:10:58 +0800107def generateTestResult(info):
108 if info['health'] == "Complete" and info['state'] == "Finished":
109 return "PASS"
110 else:
111 return "FAIL"
112
Xinyu Zhang97ee3fd2020-12-14 14:45:06 +0800113def job_links(jobs, user_args):
114 job_links = ""
115 for job, info in jobs.items():
Xinyu Zhang82dab282022-10-09 16:33:19 +0800116 job_links += "\nLAVA Test Config:\n"
117 job_links += "Config Name: {}\n".format(info['metadata']['build_name'])
118 job_links += "Test Result: {}\n".format(info['result'])
119 job_links += "Device Type: {}\n".format(info['metadata']['device_type'])
Xinyu Zhang97ee3fd2020-12-14 14:45:06 +0800120 job_links += "Build link: {}\n".format(info['metadata']['build_job_url'])
Xinyu Zhang78c146a2022-09-05 19:06:40 +0800121 job_links += "LAVA link: {}\n".format(lava_id_to_url(job, user_args))
Xinyu Zhang82dab282022-10-09 16:33:19 +0800122 job_links += "TFM LOG: {}artifact/{}/target_log.txt\n".format(os.getenv("BUILD_URL"), info['job_dir'])
Xinyu Zhang97ee3fd2020-12-14 14:45:06 +0800123 print(job_links)
124
Xinyu Zhang1b8f5152020-11-13 16:10:58 +0800125def csv_report(jobs):
126 lava_jobs = []
127 for job, info in jobs.items():
128 exist = False
129 for record in lava_jobs:
130 if info['metadata']['platform'] == record["Platform"] and \
131 info['metadata']['compiler'] == record["Compiler"] and \
132 info['metadata']['build_type'] == record["Build Type"]:
Xinyu Zhang22a12752022-10-10 17:21:21 +0800133 if record[info['metadata']['build_name']] != "FAIL":
134 record[info['metadata']['build_name']] = generateTestResult(info)
Xinyu Zhang1b8f5152020-11-13 16:10:58 +0800135 exist = True
136 break
137 if not exist:
138 record = {}
139 record["Platform"] = info['metadata']['platform']
140 record["Compiler"] = info['metadata']['compiler']
141 record["Build Type"] = info['metadata']['build_type']
Xinyu Zhang22a12752022-10-10 17:21:21 +0800142 record["Config Name"] = info['metadata']['build_name']
Xinyu Zhang1b8f5152020-11-13 16:10:58 +0800143 for cfg in cfgs:
144 record[cfg] = "N.A."
145 record[info['metadata']['name']] = generateTestResult(info)
146 lava_jobs.append(record)
147 lava_jobs.sort(key=lambda x: x["Platform"] + x["Compiler"] + x["Build Type"])
148 with open("test_results.csv", "w", newline="") as csvfile:
Xinyu Zhang22a12752022-10-10 17:21:21 +0800149 fieldnames = ["Platform", "Compiler", "Build Type"] + list(cfgs)
Xinyu Zhang1b8f5152020-11-13 16:10:58 +0800150 writer = csv.DictWriter(csvfile, fieldnames=fieldnames, extrasaction='ignore')
151
152 writer.writeheader()
153 writer.writerows(lava_jobs)
154
Matthew Hartfb6fd362020-03-04 21:03:59 +0000155
Xinyu Zhang38a18872020-11-23 16:45:28 +0800156def failure_report(jobs, user_args):
157 failed_report = "FAILURE_TESTS:"
158 for job, info in jobs.items():
159 if info['health'] != "Complete" or info['state'] != "Finished":
Xinyu Zhange9033f62022-10-08 11:15:27 +0800160 failed_report += " {}:{}artifact/{}/target_log.txt\n".format(info['metadata']['build_name'],
161 os.getenv("BUILD_URL"),
162 info['job_dir'])
Xinyu Zhang82dab282022-10-09 16:33:19 +0800163 info['result'] = 'FAILURE'
164 else:
165 info['result'] = 'SUCCESS'
Xinyu Zhang38a18872020-11-23 16:45:28 +0800166 print(failed_report)
167
Matthew Hartfb6fd362020-03-04 21:03:59 +0000168def remove_lava_dupes(results):
169 for result in results:
170 if result['result'] != 'pass':
171 if result['suite'] == "lava":
172 for other in [x for x in results if x != result]:
173 if other['name'] == result['name']:
174 if other['result'] == 'pass':
175 results.remove(result)
176 return(results)
177
Paul Sokolovsky451f67b2022-03-08 19:44:41 +0300178def test_report(jobs, user_args):
Matthew Hartfb6fd362020-03-04 21:03:59 +0000179 # parsing of test results is WIP
180 fail_j = []
181 jinja_data = []
182 for job, info in jobs.items():
Xinyu Zhang82dab282022-10-09 16:33:19 +0800183 if info['health'] != 'Complete':
184 fail_j.append(job)
185 continue
Matthew Hart4a4f1202020-06-12 15:52:46 +0100186 results_file = os.path.join(info['job_dir'], 'results.yaml')
187 if not os.path.exists(results_file) or (os.path.getsize(results_file) == 0):
188 fail_j.append(job)
189 continue
190 with open(results_file, "r") as F:
191 res_data = F.read()
Paul Sokolovskyf2f385d2022-01-11 00:36:31 +0300192 results = yaml.safe_load(res_data)
Paul Sokolovsky07f6dfb2022-07-15 12:26:24 +0300193 non_lava_results = [x for x in results if x['suite'] != 'lava' or x['name'] == 'lava-test-monitor']
Matthew Hartfb6fd362020-03-04 21:03:59 +0000194 info['lava_url'] = lava_id_to_url(job, user_args)
Arthur She38d5f5a2022-09-02 17:32:14 -0700195 info['artifacts_dir'] = info['job_dir']
Matthew Hartfb6fd362020-03-04 21:03:59 +0000196 jinja_data.append({job: [info, non_lava_results]})
197 for result in non_lava_results:
Paul Sokolovsky58f00de2022-02-01 00:26:32 +0300198 if result['result'] == 'fail':
Matthew Hartfb6fd362020-03-04 21:03:59 +0000199 fail_j.append(job) if job not in fail_j else fail_j
200 time.sleep(0.5) # be friendly to LAVA
Matthew Hartfb6fd362020-03-04 21:03:59 +0000201 data = {}
202 data['jobs'] = jinja_data
203 render_jinja(data)
204
205def render_jinja(data):
206 work_dir = os.path.join(os.path.abspath(os.path.dirname(__file__)), "jinja2_templates")
207 template_loader = FileSystemLoader(searchpath=work_dir)
208 template_env = Environment(loader=template_loader)
209 html = template_env.get_template("test_summary.jinja2").render(data)
210 csv = template_env.get_template("test_summary_csv.jinja2").render(data)
211 with open('test_summary.html', "w") as F:
212 F.write(html)
213 with open('test_summary.csv', "w") as F:
214 F.write(csv)
215
216def print_lava_urls(jobs, user_args):
217 output = [lava_id_to_url(x, user_args) for x in jobs]
Xinyu Zhang78c146a2022-09-05 19:06:40 +0800218 info_print("LAVA jobs triggered for this build: {}".format(output))
Matthew Hartfb6fd362020-03-04 21:03:59 +0000219
220
Xinyu Zhang78c146a2022-09-05 19:06:40 +0800221def info_print(line, silent=True):
222 if not silent:
223 print("INFO: {}".format(line))
Matthew Hartfb6fd362020-03-04 21:03:59 +0000224
225def main(user_args):
226 """ Main logic """
Xinyu Zhang3e8f6602021-04-28 10:57:32 +0800227 for try_time in range(3):
228 try:
Paul Sokolovsky451f67b2022-03-08 19:44:41 +0300229 finished_jobs = wait_for_jobs(user_args)
Xinyu Zhang3e8f6602021-04-28 10:57:32 +0800230 break
231 except Exception as e:
Xinyu Zhang3e8f6602021-04-28 10:57:32 +0800232 if try_time < 2:
Paul Sokolovskycc51ea92022-02-02 19:34:02 +0300233 print("Exception in wait_for_jobs: {!r}".format(e))
234 print("Trying to get LAVA jobs again...")
Xinyu Zhang3e8f6602021-04-28 10:57:32 +0800235 else:
236 raise e
Paul Sokolovsky451f67b2022-03-08 19:44:41 +0300237 process_finished_jobs(finished_jobs, user_args)
Matthew Hartfb6fd362020-03-04 21:03:59 +0000238
239def get_cmd_args():
240 """ Parse command line arguments """
241
242 # Parse command line arguments to override config
243 parser = argparse.ArgumentParser(description="Lava Wait Jobs")
244 cmdargs = parser.add_argument_group("Lava Wait Jobs")
245
246 # Configuration control
247 cmdargs.add_argument(
248 "--lava-url", dest="lava_url", action="store", help="LAVA lab URL (without RPC2)"
249 )
250 cmdargs.add_argument(
251 "--job-ids", dest="job_ids", action="store", required=True, help="Comma separated list of job IDS"
252 )
253 cmdargs.add_argument(
Xinyu Zhangf2b7cbf2021-05-18 20:17:34 +0800254 "--lava-token", dest="lava_token", action="store", help="LAVA auth token"
Matthew Hartfb6fd362020-03-04 21:03:59 +0000255 )
256 cmdargs.add_argument(
Xinyu Zhangf2b7cbf2021-05-18 20:17:34 +0800257 "--lava-user", dest="lava_user", action="store", help="LAVA username"
Matthew Hartfb6fd362020-03-04 21:03:59 +0000258 )
259 cmdargs.add_argument(
260 "--use-env", dest="token_from_env", action="store_true", default=False, help="Use LAVA auth info from environment"
261 )
262 cmdargs.add_argument(
263 "--lava-timeout", dest="dispatch_timeout", action="store", type=int, default=3600, help="Time in seconds to wait for all jobs"
264 )
265 cmdargs.add_argument(
266 "--artifacts-path", dest="artifacts_path", action="store", help="Download LAVA artifacts to this directory"
267 )
268 return parser.parse_args()
269
270
271if __name__ == "__main__":
272 main(get_cmd_args())