blob: 82ebf38e584b5463c52a311329b388fb209c8ba7 [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 *
Matthew Hartfb6fd362020-03-04 21:03:59 +000029
30try:
31 from tfm_ci_pylib.utils import save_json, load_json, sort_dict,\
32 load_yaml, test, print_test
33 from tfm_ci_pylib.lava_rpc_connector import LAVA_RPC_connector
34except ImportError:
35 dir_path = os.path.dirname(os.path.realpath(__file__))
36 sys.path.append(os.path.join(dir_path, "../"))
37 from tfm_ci_pylib.utils import save_json, load_json, sort_dict,\
38 load_yaml, test, print_test
39 from tfm_ci_pylib.lava_rpc_connector import LAVA_RPC_connector
40
Xinyu Zhang1b8f5152020-11-13 16:10:58 +080041cfgs = ["Default", "CoreIPC", "CoreIPCTfmLevel2", "CoreIPCTfmLevel3",
42 "Regression", "RegressionIPC",
43 "RegressionIPCTfmLevel2", "RegressionIPCTfmLevel3",
44 "DefaultProfileS", "RegressionProfileS",
45 "DefaultProfileM", "RegressionProfileM", "RegressionProfileM PSOFF",
Xinyu Zhang9b1aef92021-03-12 15:36:44 +080046 "DefaultProfileL", "RegressionProfileL",
Xinyu Zhang1b8f5152020-11-13 16:10:58 +080047 "PsaApiTest (Attest)", "PsaApiTestIPC (Attest)",
48 "PsaApiTestIPCTfmLevel2 (Attest)",
49 "PsaApiTest (Crypto)", "PsaApiTestIPC (Crypto)",
50 "PsaApiTestIPCTfmLevel2 (Crypto)",
51 "PsaApiTest (PS)", "PsaApiTestIPC (PS)",
52 "PsaApiTestIPCTfmLevel2 (PS)",
53 "PsaApiTest (ITS)", "PsaApiTestIPC (ITS)",
54 "PsaApiTestIPCTfmLevel2 (ITS)",
55 "PsaApiTestIPC (FF)",
56 "PsaApiTestIPCTfmLevel2 (FF)",
57 "PsaApiTestIPCTfmLevel3 (ITS)", "PsaApiTestIPCTfmLevel3 (PS)",
58 "PsaApiTestIPCTfmLevel3 (Crypto)", "PsaApiTestIPCTfmLevel3 (Attest)",
59 "PsaApiTestIPCTfmLevel3 (FF)"]
60
Matthew Hartfb6fd362020-03-04 21:03:59 +000061def wait_for_jobs(user_args):
62 job_list = user_args.job_ids.split(",")
63 job_list = [int(x) for x in job_list if x != '']
64 lava = test_lava_dispatch_credentials(user_args)
Xinyu Zhangf2b7cbf2021-05-18 20:17:34 +080065 finished_jobs = get_finished_jobs(job_list, user_args, lava)
Xinyu Zhangc8a670c2021-05-18 20:20:53 +080066 resubmit_jobs = resubmit_failed_jobs(finished_jobs, user_args)
67 finished_resubmit_jobs = get_finished_jobs(resubmit_jobs, user_args, lava)
68 finished_jobs.update(finished_resubmit_jobs)
Xinyu Zhangf2b7cbf2021-05-18 20:17:34 +080069 print_lava_urls(finished_jobs, user_args)
70 job_links(finished_jobs, user_args)
71 boot_report(finished_jobs, user_args)
72 test_report(finished_jobs, user_args, lava)
73 failure_report(finished_jobs, user_args)
74 csv_report(finished_jobs)
75
76def get_finished_jobs(job_list, user_args, lava):
Matthew Hartfb6fd362020-03-04 21:03:59 +000077 finished_jobs = lava.block_wait_for_jobs(job_list, user_args.dispatch_timeout, 0.5)
78 unfinished_jobs = [item for item in job_list if item not in finished_jobs]
79 for job in unfinished_jobs:
80 info_print("Cancelling unfinished job: {}".format(job))
81 lava.cancel_job(job)
82 if user_args.artifacts_path:
83 for job, info in finished_jobs.items():
84 info['job_dir'] = os.path.join(user_args.artifacts_path, "{}_{}".format(str(job), info['description']))
85 finished_jobs[job] = info
86 finished_jobs = fetch_artifacts(finished_jobs, user_args, lava)
Xinyu Zhangf2b7cbf2021-05-18 20:17:34 +080087 return finished_jobs
Matthew Hartfb6fd362020-03-04 21:03:59 +000088
Xinyu Zhangc8a670c2021-05-18 20:20:53 +080089def resubmit_failed_jobs(jobs, user_args):
90 if not jobs:
91 return []
Xinyu Zhang4aca6d02021-05-31 11:43:32 +080092 time.sleep(2) # be friendly to LAVA
Xinyu Zhangc8a670c2021-05-18 20:20:53 +080093 failed_job = []
94 os.makedirs('failed_jobs', exist_ok=True)
95 for job_id, info in jobs.items():
96 if not (info['health'] == "Complete" and info['state'] == "Finished"):
97 job_dir = info['job_dir']
98 def_path = os.path.join(job_dir, 'definition.yaml')
99 os.rename(def_path, 'failed_jobs/{}_definition.yaml'.format(job_id))
100 shutil.rmtree(job_dir)
101 failed_job.append(job_id)
102 for failed_job_id in failed_job:
103 jobs.pop(failed_job_id)
104 resubmitted_jobs = lava_dispatch(user_args, job_dir='failed_jobs')
105 resubmitted_jobs = [int(x) for x in resubmitted_jobs if x != '']
106 return resubmitted_jobs
107
Matthew Hartfb6fd362020-03-04 21:03:59 +0000108def fetch_artifacts(jobs, user_args, lava):
109 if not user_args.artifacts_path:
110 return
111 for job_id, info in jobs.items():
112 job_dir = info['job_dir']
113 info_print("Fetching artifacts for JOB: {} to {}".format(job_id, job_dir))
114 os.makedirs(job_dir, exist_ok=True)
115 def_path = os.path.join(job_dir, 'definition.yaml')
116 target_log = os.path.join(job_dir, 'target_log.txt')
Matthew Hart4a4f1202020-06-12 15:52:46 +0100117 config = os.path.join(job_dir, 'config.tar.bz2')
118 results_file = os.path.join(job_dir, 'results.yaml')
Matthew Hartfb6fd362020-03-04 21:03:59 +0000119 definition, metadata = lava.get_job_definition(job_id, def_path)
120 jobs[job_id]['metadata'] = metadata
121 time.sleep(0.2) # be friendly to LAVA
Matthew Hart4a4f1202020-06-12 15:52:46 +0100122 lava.get_job_log(job_id, target_log)
Matthew Hartfb6fd362020-03-04 21:03:59 +0000123 time.sleep(0.2)
124 lava.get_job_config(job_id, config)
125 time.sleep(0.2)
Matthew Hart4a4f1202020-06-12 15:52:46 +0100126 lava.get_job_results(job_id, results_file)
Matthew Hartfb6fd362020-03-04 21:03:59 +0000127 return(jobs)
128
129
130def lava_id_to_url(id, user_args):
131 return "{}/scheduler/job/{}".format(user_args.lava_url, id)
132
Xinyu Zhang1b8f5152020-11-13 16:10:58 +0800133def generateTestResult(info):
134 if info['health'] == "Complete" and info['state'] == "Finished":
135 return "PASS"
136 else:
137 return "FAIL"
138
Xinyu Zhang97ee3fd2020-12-14 14:45:06 +0800139def job_links(jobs, user_args):
140 job_links = ""
141 for job, info in jobs.items():
142 job_links += "Build Config: {} ".format(info['metadata']['build_name'])
143 job_links += "LAVA link: {} ".format(lava_id_to_url(job, user_args))
144 job_links += "Build link: {}\n".format(info['metadata']['build_job_url'])
145 print(job_links)
146
Xinyu Zhang1b8f5152020-11-13 16:10:58 +0800147def csv_report(jobs):
148 lava_jobs = []
149 for job, info in jobs.items():
150 exist = False
151 for record in lava_jobs:
152 if info['metadata']['platform'] == record["Platform"] and \
153 info['metadata']['compiler'] == record["Compiler"] and \
154 info['metadata']['build_type'] == record["Build Type"]:
155 if record[info['metadata']['name']] != "FAIL":
156 record[info['metadata']['name']] = generateTestResult(info)
157 exist = True
158 break
159 if not exist:
160 record = {}
161 record["Platform"] = info['metadata']['platform']
162 record["Compiler"] = info['metadata']['compiler']
163 record["Build Type"] = info['metadata']['build_type']
164 record["Config Name"] = info['metadata']['name']
165 for cfg in cfgs:
166 record[cfg] = "N.A."
167 record[info['metadata']['name']] = generateTestResult(info)
168 lava_jobs.append(record)
169 lava_jobs.sort(key=lambda x: x["Platform"] + x["Compiler"] + x["Build Type"])
170 with open("test_results.csv", "w", newline="") as csvfile:
171 fieldnames = ["Platform", "Compiler", "Build Type"] + cfgs
172 writer = csv.DictWriter(csvfile, fieldnames=fieldnames, extrasaction='ignore')
173
174 writer.writeheader()
175 writer.writerows(lava_jobs)
176
Matthew Hartfb6fd362020-03-04 21:03:59 +0000177def boot_report(jobs, user_args):
178 incomplete_jobs = []
179 for job, info in jobs.items():
180 if info['health'] != 'Complete':
181 if info['error_reason'] == 'Infrastructure':
182 info_print("Job {} failed with Infrastructure error".format(job))
183 incomplete_jobs.append(job)
184 incomplete_output = [lava_id_to_url(x, user_args) for x in incomplete_jobs];
185 if len(incomplete_jobs) > 0:
186 print("BOOT_RESULT: -1 Failed: {}".format(incomplete_output))
187 else:
188 print("BOOT_RESULT: +1")
189
Xinyu Zhang38a18872020-11-23 16:45:28 +0800190def failure_report(jobs, user_args):
191 failed_report = "FAILURE_TESTS:"
192 for job, info in jobs.items():
193 if info['health'] != "Complete" or info['state'] != "Finished":
194 failed_report += " {}:{}".format(info['metadata']['build_name'],
195 lava_id_to_url(job, user_args))
196 print(failed_report)
197
Matthew Hartfb6fd362020-03-04 21:03:59 +0000198def remove_lava_dupes(results):
199 for result in results:
200 if result['result'] != 'pass':
201 if result['suite'] == "lava":
202 for other in [x for x in results if x != result]:
203 if other['name'] == result['name']:
204 if other['result'] == 'pass':
205 results.remove(result)
206 return(results)
207
208def test_report(jobs, user_args, lava):
209 # parsing of test results is WIP
210 fail_j = []
211 jinja_data = []
212 for job, info in jobs.items():
Matthew Hart4a4f1202020-06-12 15:52:46 +0100213 results_file = os.path.join(info['job_dir'], 'results.yaml')
214 if not os.path.exists(results_file) or (os.path.getsize(results_file) == 0):
215 fail_j.append(job)
216 continue
217 with open(results_file, "r") as F:
218 res_data = F.read()
Paul Sokolovskyf2f385d2022-01-11 00:36:31 +0300219 results = yaml.safe_load(res_data)
Matthew Hartfb6fd362020-03-04 21:03:59 +0000220 non_lava_results = [x for x in results if x['suite'] != 'lava']
221 info['lava_url'] = lava_id_to_url(job, user_args)
222 info['artifacts_dir'] = "tf-m-ci-scripts/{}".format(info['job_dir'])
223 jinja_data.append({job: [info, non_lava_results]})
224 for result in non_lava_results:
225 if result['result'] != 'pass':
226 fail_j.append(job) if job not in fail_j else fail_j
227 time.sleep(0.5) # be friendly to LAVA
228 fail_output = [lava_id_to_url(x, user_args) for x in fail_j]
229 if len(fail_j) > 0:
230 print("TEST_RESULT: -1 Failed: {}".format(fail_output))
231 else:
232 print("TEST_RESULT: +1")
233 data = {}
234 data['jobs'] = jinja_data
235 render_jinja(data)
236
237def render_jinja(data):
238 work_dir = os.path.join(os.path.abspath(os.path.dirname(__file__)), "jinja2_templates")
239 template_loader = FileSystemLoader(searchpath=work_dir)
240 template_env = Environment(loader=template_loader)
241 html = template_env.get_template("test_summary.jinja2").render(data)
242 csv = template_env.get_template("test_summary_csv.jinja2").render(data)
243 with open('test_summary.html', "w") as F:
244 F.write(html)
245 with open('test_summary.csv', "w") as F:
246 F.write(csv)
247
248def print_lava_urls(jobs, user_args):
249 output = [lava_id_to_url(x, user_args) for x in jobs]
250 print("LAVA jobs triggered for this build: {}".format(output))
251
252
253def info_print(line):
254 print("INFO: {}".format(line))
255
256def main(user_args):
257 """ Main logic """
258 user_args.lava_rpc = "RPC2"
Xinyu Zhang3e8f6602021-04-28 10:57:32 +0800259 for try_time in range(3):
260 try:
261 wait_for_jobs(user_args)
262 break
263 except Exception as e:
264 print(e)
265 if try_time < 2:
266 print("Try to get LAVA jobs again...")
267 else:
268 raise e
Matthew Hartfb6fd362020-03-04 21:03:59 +0000269
270def get_cmd_args():
271 """ Parse command line arguments """
272
273 # Parse command line arguments to override config
274 parser = argparse.ArgumentParser(description="Lava Wait Jobs")
275 cmdargs = parser.add_argument_group("Lava Wait Jobs")
276
277 # Configuration control
278 cmdargs.add_argument(
279 "--lava-url", dest="lava_url", action="store", help="LAVA lab URL (without RPC2)"
280 )
281 cmdargs.add_argument(
282 "--job-ids", dest="job_ids", action="store", required=True, help="Comma separated list of job IDS"
283 )
284 cmdargs.add_argument(
Xinyu Zhangf2b7cbf2021-05-18 20:17:34 +0800285 "--lava-token", dest="lava_token", action="store", help="LAVA auth token"
Matthew Hartfb6fd362020-03-04 21:03:59 +0000286 )
287 cmdargs.add_argument(
Xinyu Zhangf2b7cbf2021-05-18 20:17:34 +0800288 "--lava-user", dest="lava_user", action="store", help="LAVA username"
Matthew Hartfb6fd362020-03-04 21:03:59 +0000289 )
290 cmdargs.add_argument(
291 "--use-env", dest="token_from_env", action="store_true", default=False, help="Use LAVA auth info from environment"
292 )
293 cmdargs.add_argument(
294 "--lava-timeout", dest="dispatch_timeout", action="store", type=int, default=3600, help="Time in seconds to wait for all jobs"
295 )
296 cmdargs.add_argument(
297 "--artifacts-path", dest="artifacts_path", action="store", help="Download LAVA artifacts to this directory"
298 )
299 return parser.parse_args()
300
301
302if __name__ == "__main__":
303 main(get_cmd_args())