blob: 6f70d28144dc38c99c8069f8ee48929e93cd86f2 [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 Zhangf2b7cbf2021-05-18 20:17:34 +08007 * Copyright (c) 2020-2021, 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
19import sys
Matthew Hartfb6fd362020-03-04 21:03:59 +000020import time
21import yaml
22import argparse
Xinyu Zhang1b8f5152020-11-13 16:10:58 +080023import csv
Xinyu Zhangc8a670c2021-05-18 20:20:53 +080024import shutil
Matthew Hartfb6fd362020-03-04 21:03:59 +000025from jinja2 import Environment, FileSystemLoader
26from lava_helper_configs import *
27from lava_helper import test_lava_dispatch_credentials
Xinyu Zhangc8a670c2021-05-18 20:20:53 +080028from lava_submit_jobs import *
Paul Sokolovsky2512ec52022-03-04 00:15:39 +030029import codecov_helper
30
Matthew Hartfb6fd362020-03-04 21:03:59 +000031
32try:
33 from tfm_ci_pylib.utils import save_json, load_json, sort_dict,\
34 load_yaml, test, print_test
35 from tfm_ci_pylib.lava_rpc_connector import LAVA_RPC_connector
36except ImportError:
37 dir_path = os.path.dirname(os.path.realpath(__file__))
38 sys.path.append(os.path.join(dir_path, "../"))
39 from tfm_ci_pylib.utils import save_json, load_json, sort_dict,\
40 load_yaml, test, print_test
41 from tfm_ci_pylib.lava_rpc_connector import LAVA_RPC_connector
42
Xinyu Zhang1b8f5152020-11-13 16:10:58 +080043cfgs = ["Default", "CoreIPC", "CoreIPCTfmLevel2", "CoreIPCTfmLevel3",
44 "Regression", "RegressionIPC",
45 "RegressionIPCTfmLevel2", "RegressionIPCTfmLevel3",
46 "DefaultProfileS", "RegressionProfileS",
47 "DefaultProfileM", "RegressionProfileM", "RegressionProfileM PSOFF",
Xinyu Zhang9b1aef92021-03-12 15:36:44 +080048 "DefaultProfileL", "RegressionProfileL",
Xinyu Zhang1b8f5152020-11-13 16:10:58 +080049 "PsaApiTest (Attest)", "PsaApiTestIPC (Attest)",
50 "PsaApiTestIPCTfmLevel2 (Attest)",
51 "PsaApiTest (Crypto)", "PsaApiTestIPC (Crypto)",
52 "PsaApiTestIPCTfmLevel2 (Crypto)",
53 "PsaApiTest (PS)", "PsaApiTestIPC (PS)",
54 "PsaApiTestIPCTfmLevel2 (PS)",
55 "PsaApiTest (ITS)", "PsaApiTestIPC (ITS)",
56 "PsaApiTestIPCTfmLevel2 (ITS)",
57 "PsaApiTestIPC (FF)",
58 "PsaApiTestIPCTfmLevel2 (FF)",
Paul Sokolovskyb6003112022-02-04 00:36:14 +030059 "PsaApiTest (STORAGE)",
60 "PsaApiTestIPC (STORAGE)",
61 "PsaApiTestIPCTfmLevel2 (STORAGE)",
62 "PsaApiTestIPCTfmLevel3 (STORAGE)",
Xinyu Zhang1b8f5152020-11-13 16:10:58 +080063 "PsaApiTestIPCTfmLevel3 (ITS)", "PsaApiTestIPCTfmLevel3 (PS)",
64 "PsaApiTestIPCTfmLevel3 (Crypto)", "PsaApiTestIPCTfmLevel3 (Attest)",
65 "PsaApiTestIPCTfmLevel3 (FF)"]
66
Paul Sokolovskyf1ff6c12022-02-02 21:42:41 +030067# Convert test config identifiers to LAVA naming convention.
68cfgs = [x.replace(" (", "_").replace(")", "") for x in cfgs]
69
Matthew Hartfb6fd362020-03-04 21:03:59 +000070def wait_for_jobs(user_args):
71 job_list = user_args.job_ids.split(",")
72 job_list = [int(x) for x in job_list if x != '']
73 lava = test_lava_dispatch_credentials(user_args)
Xinyu Zhangf2b7cbf2021-05-18 20:17:34 +080074 finished_jobs = get_finished_jobs(job_list, user_args, lava)
Xinyu Zhangc8a670c2021-05-18 20:20:53 +080075 resubmit_jobs = resubmit_failed_jobs(finished_jobs, user_args)
Paul Sokolovskyc87beee2022-04-30 08:50:47 +030076 if resubmit_jobs:
77 info_print("Waiting for resubmitted jobs: {}".format(resubmit_jobs))
78 finished_resubmit_jobs = get_finished_jobs(resubmit_jobs, user_args, lava)
79 finished_jobs.update(finished_resubmit_jobs)
Paul Sokolovsky451f67b2022-03-08 19:44:41 +030080 return finished_jobs
81
82
83def process_finished_jobs(finished_jobs, user_args):
Xinyu Zhangf2b7cbf2021-05-18 20:17:34 +080084 print_lava_urls(finished_jobs, user_args)
85 job_links(finished_jobs, user_args)
86 boot_report(finished_jobs, user_args)
Paul Sokolovsky451f67b2022-03-08 19:44:41 +030087 test_report(finished_jobs, user_args)
Xinyu Zhangf2b7cbf2021-05-18 20:17:34 +080088 failure_report(finished_jobs, user_args)
89 csv_report(finished_jobs)
Paul Sokolovsky2512ec52022-03-04 00:15:39 +030090 codecov_helper.coverage_reports(finished_jobs, user_args)
Xinyu Zhangf2b7cbf2021-05-18 20:17:34 +080091
Paul Sokolovsky451f67b2022-03-08 19:44:41 +030092
Xinyu Zhangf2b7cbf2021-05-18 20:17:34 +080093def get_finished_jobs(job_list, user_args, lava):
Paul Sokolovsky697f9552022-05-05 10:44:27 +030094 finished_jobs = lava.block_wait_for_jobs(job_list, user_args.dispatch_timeout, 5)
Matthew Hartfb6fd362020-03-04 21:03:59 +000095 unfinished_jobs = [item for item in job_list if item not in finished_jobs]
96 for job in unfinished_jobs:
97 info_print("Cancelling unfinished job: {}".format(job))
98 lava.cancel_job(job)
99 if user_args.artifacts_path:
100 for job, info in finished_jobs.items():
101 info['job_dir'] = os.path.join(user_args.artifacts_path, "{}_{}".format(str(job), info['description']))
102 finished_jobs[job] = info
103 finished_jobs = fetch_artifacts(finished_jobs, user_args, lava)
Xinyu Zhangf2b7cbf2021-05-18 20:17:34 +0800104 return finished_jobs
Matthew Hartfb6fd362020-03-04 21:03:59 +0000105
Xinyu Zhangc8a670c2021-05-18 20:20:53 +0800106def resubmit_failed_jobs(jobs, user_args):
107 if not jobs:
108 return []
Xinyu Zhang4aca6d02021-05-31 11:43:32 +0800109 time.sleep(2) # be friendly to LAVA
Xinyu Zhangc8a670c2021-05-18 20:20:53 +0800110 failed_job = []
111 os.makedirs('failed_jobs', exist_ok=True)
112 for job_id, info in jobs.items():
113 if not (info['health'] == "Complete" and info['state'] == "Finished"):
114 job_dir = info['job_dir']
115 def_path = os.path.join(job_dir, 'definition.yaml')
116 os.rename(def_path, 'failed_jobs/{}_definition.yaml'.format(job_id))
117 shutil.rmtree(job_dir)
118 failed_job.append(job_id)
119 for failed_job_id in failed_job:
120 jobs.pop(failed_job_id)
121 resubmitted_jobs = lava_dispatch(user_args, job_dir='failed_jobs')
122 resubmitted_jobs = [int(x) for x in resubmitted_jobs if x != '']
123 return resubmitted_jobs
124
Paul Sokolovskyc2d6d882022-02-25 19:11:18 +0300125
Matthew Hartfb6fd362020-03-04 21:03:59 +0000126def fetch_artifacts(jobs, user_args, lava):
127 if not user_args.artifacts_path:
128 return
129 for job_id, info in jobs.items():
130 job_dir = info['job_dir']
131 info_print("Fetching artifacts for JOB: {} to {}".format(job_id, job_dir))
132 os.makedirs(job_dir, exist_ok=True)
133 def_path = os.path.join(job_dir, 'definition.yaml')
134 target_log = os.path.join(job_dir, 'target_log.txt')
Matthew Hart4a4f1202020-06-12 15:52:46 +0100135 config = os.path.join(job_dir, 'config.tar.bz2')
136 results_file = os.path.join(job_dir, 'results.yaml')
Matthew Hartfb6fd362020-03-04 21:03:59 +0000137 definition, metadata = lava.get_job_definition(job_id, def_path)
138 jobs[job_id]['metadata'] = metadata
139 time.sleep(0.2) # be friendly to LAVA
Matthew Hart4a4f1202020-06-12 15:52:46 +0100140 lava.get_job_log(job_id, target_log)
Matthew Hartfb6fd362020-03-04 21:03:59 +0000141 time.sleep(0.2)
142 lava.get_job_config(job_id, config)
143 time.sleep(0.2)
Matthew Hart4a4f1202020-06-12 15:52:46 +0100144 lava.get_job_results(job_id, results_file)
Paul Sokolovskyc2d6d882022-02-25 19:11:18 +0300145 codecov_helper.extract_trace_data(target_log, job_dir)
Matthew Hartfb6fd362020-03-04 21:03:59 +0000146 return(jobs)
147
148
149def lava_id_to_url(id, user_args):
150 return "{}/scheduler/job/{}".format(user_args.lava_url, id)
151
Xinyu Zhang1b8f5152020-11-13 16:10:58 +0800152def generateTestResult(info):
153 if info['health'] == "Complete" and info['state'] == "Finished":
154 return "PASS"
155 else:
156 return "FAIL"
157
Xinyu Zhang97ee3fd2020-12-14 14:45:06 +0800158def job_links(jobs, user_args):
159 job_links = ""
160 for job, info in jobs.items():
161 job_links += "Build Config: {} ".format(info['metadata']['build_name'])
162 job_links += "LAVA link: {} ".format(lava_id_to_url(job, user_args))
163 job_links += "Build link: {}\n".format(info['metadata']['build_job_url'])
164 print(job_links)
165
Xinyu Zhang1b8f5152020-11-13 16:10:58 +0800166def csv_report(jobs):
167 lava_jobs = []
168 for job, info in jobs.items():
169 exist = False
170 for record in lava_jobs:
171 if info['metadata']['platform'] == record["Platform"] and \
172 info['metadata']['compiler'] == record["Compiler"] and \
173 info['metadata']['build_type'] == record["Build Type"]:
174 if record[info['metadata']['name']] != "FAIL":
175 record[info['metadata']['name']] = generateTestResult(info)
176 exist = True
177 break
178 if not exist:
179 record = {}
180 record["Platform"] = info['metadata']['platform']
181 record["Compiler"] = info['metadata']['compiler']
182 record["Build Type"] = info['metadata']['build_type']
183 record["Config Name"] = info['metadata']['name']
184 for cfg in cfgs:
185 record[cfg] = "N.A."
186 record[info['metadata']['name']] = generateTestResult(info)
187 lava_jobs.append(record)
188 lava_jobs.sort(key=lambda x: x["Platform"] + x["Compiler"] + x["Build Type"])
189 with open("test_results.csv", "w", newline="") as csvfile:
190 fieldnames = ["Platform", "Compiler", "Build Type"] + cfgs
191 writer = csv.DictWriter(csvfile, fieldnames=fieldnames, extrasaction='ignore')
192
193 writer.writeheader()
194 writer.writerows(lava_jobs)
195
Matthew Hartfb6fd362020-03-04 21:03:59 +0000196def boot_report(jobs, user_args):
197 incomplete_jobs = []
198 for job, info in jobs.items():
199 if info['health'] != 'Complete':
200 if info['error_reason'] == 'Infrastructure':
201 info_print("Job {} failed with Infrastructure error".format(job))
202 incomplete_jobs.append(job)
203 incomplete_output = [lava_id_to_url(x, user_args) for x in incomplete_jobs];
204 if len(incomplete_jobs) > 0:
205 print("BOOT_RESULT: -1 Failed: {}".format(incomplete_output))
206 else:
207 print("BOOT_RESULT: +1")
208
Xinyu Zhang38a18872020-11-23 16:45:28 +0800209def failure_report(jobs, user_args):
210 failed_report = "FAILURE_TESTS:"
211 for job, info in jobs.items():
212 if info['health'] != "Complete" or info['state'] != "Finished":
213 failed_report += " {}:{}".format(info['metadata']['build_name'],
214 lava_id_to_url(job, user_args))
215 print(failed_report)
216
Matthew Hartfb6fd362020-03-04 21:03:59 +0000217def remove_lava_dupes(results):
218 for result in results:
219 if result['result'] != 'pass':
220 if result['suite'] == "lava":
221 for other in [x for x in results if x != result]:
222 if other['name'] == result['name']:
223 if other['result'] == 'pass':
224 results.remove(result)
225 return(results)
226
Paul Sokolovsky451f67b2022-03-08 19:44:41 +0300227def test_report(jobs, user_args):
Matthew Hartfb6fd362020-03-04 21:03:59 +0000228 # parsing of test results is WIP
229 fail_j = []
230 jinja_data = []
231 for job, info in jobs.items():
Matthew Hart4a4f1202020-06-12 15:52:46 +0100232 results_file = os.path.join(info['job_dir'], 'results.yaml')
233 if not os.path.exists(results_file) or (os.path.getsize(results_file) == 0):
234 fail_j.append(job)
235 continue
236 with open(results_file, "r") as F:
237 res_data = F.read()
Paul Sokolovskyf2f385d2022-01-11 00:36:31 +0300238 results = yaml.safe_load(res_data)
Paul Sokolovsky07f6dfb2022-07-15 12:26:24 +0300239 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 +0000240 info['lava_url'] = lava_id_to_url(job, user_args)
Arthur She38d5f5a2022-09-02 17:32:14 -0700241 info['artifacts_dir'] = info['job_dir']
Matthew Hartfb6fd362020-03-04 21:03:59 +0000242 jinja_data.append({job: [info, non_lava_results]})
243 for result in non_lava_results:
Paul Sokolovsky58f00de2022-02-01 00:26:32 +0300244 if result['result'] == 'fail':
Matthew Hartfb6fd362020-03-04 21:03:59 +0000245 fail_j.append(job) if job not in fail_j else fail_j
246 time.sleep(0.5) # be friendly to LAVA
247 fail_output = [lava_id_to_url(x, user_args) for x in fail_j]
248 if len(fail_j) > 0:
249 print("TEST_RESULT: -1 Failed: {}".format(fail_output))
250 else:
251 print("TEST_RESULT: +1")
252 data = {}
253 data['jobs'] = jinja_data
254 render_jinja(data)
255
256def render_jinja(data):
257 work_dir = os.path.join(os.path.abspath(os.path.dirname(__file__)), "jinja2_templates")
258 template_loader = FileSystemLoader(searchpath=work_dir)
259 template_env = Environment(loader=template_loader)
260 html = template_env.get_template("test_summary.jinja2").render(data)
261 csv = template_env.get_template("test_summary_csv.jinja2").render(data)
262 with open('test_summary.html', "w") as F:
263 F.write(html)
264 with open('test_summary.csv', "w") as F:
265 F.write(csv)
266
267def print_lava_urls(jobs, user_args):
268 output = [lava_id_to_url(x, user_args) for x in jobs]
269 print("LAVA jobs triggered for this build: {}".format(output))
270
271
272def info_print(line):
273 print("INFO: {}".format(line))
274
275def main(user_args):
276 """ Main logic """
277 user_args.lava_rpc = "RPC2"
Xinyu Zhang3e8f6602021-04-28 10:57:32 +0800278 for try_time in range(3):
279 try:
Paul Sokolovsky451f67b2022-03-08 19:44:41 +0300280 finished_jobs = wait_for_jobs(user_args)
Xinyu Zhang3e8f6602021-04-28 10:57:32 +0800281 break
282 except Exception as e:
Xinyu Zhang3e8f6602021-04-28 10:57:32 +0800283 if try_time < 2:
Paul Sokolovskycc51ea92022-02-02 19:34:02 +0300284 print("Exception in wait_for_jobs: {!r}".format(e))
285 print("Trying to get LAVA jobs again...")
Xinyu Zhang3e8f6602021-04-28 10:57:32 +0800286 else:
287 raise e
Paul Sokolovsky451f67b2022-03-08 19:44:41 +0300288 process_finished_jobs(finished_jobs, user_args)
Matthew Hartfb6fd362020-03-04 21:03:59 +0000289
290def get_cmd_args():
291 """ Parse command line arguments """
292
293 # Parse command line arguments to override config
294 parser = argparse.ArgumentParser(description="Lava Wait Jobs")
295 cmdargs = parser.add_argument_group("Lava Wait Jobs")
296
297 # Configuration control
298 cmdargs.add_argument(
299 "--lava-url", dest="lava_url", action="store", help="LAVA lab URL (without RPC2)"
300 )
301 cmdargs.add_argument(
302 "--job-ids", dest="job_ids", action="store", required=True, help="Comma separated list of job IDS"
303 )
304 cmdargs.add_argument(
Xinyu Zhangf2b7cbf2021-05-18 20:17:34 +0800305 "--lava-token", dest="lava_token", action="store", help="LAVA auth token"
Matthew Hartfb6fd362020-03-04 21:03:59 +0000306 )
307 cmdargs.add_argument(
Xinyu Zhangf2b7cbf2021-05-18 20:17:34 +0800308 "--lava-user", dest="lava_user", action="store", help="LAVA username"
Matthew Hartfb6fd362020-03-04 21:03:59 +0000309 )
310 cmdargs.add_argument(
311 "--use-env", dest="token_from_env", action="store_true", default=False, help="Use LAVA auth info from environment"
312 )
313 cmdargs.add_argument(
314 "--lava-timeout", dest="dispatch_timeout", action="store", type=int, default=3600, help="Time in seconds to wait for all jobs"
315 )
316 cmdargs.add_argument(
317 "--artifacts-path", dest="artifacts_path", action="store", help="Download LAVA artifacts to this directory"
318 )
319 return parser.parse_args()
320
321
322if __name__ == "__main__":
323 main(get_cmd_args())