blob: 5f0ae42bf5354272b912d11dcf594d932f3168ad [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 []
92 failed_job = []
93 os.makedirs('failed_jobs', exist_ok=True)
94 for job_id, info in jobs.items():
95 if not (info['health'] == "Complete" and info['state'] == "Finished"):
96 job_dir = info['job_dir']
97 def_path = os.path.join(job_dir, 'definition.yaml')
98 os.rename(def_path, 'failed_jobs/{}_definition.yaml'.format(job_id))
99 shutil.rmtree(job_dir)
100 failed_job.append(job_id)
101 for failed_job_id in failed_job:
102 jobs.pop(failed_job_id)
103 resubmitted_jobs = lava_dispatch(user_args, job_dir='failed_jobs')
104 resubmitted_jobs = [int(x) for x in resubmitted_jobs if x != '']
105 return resubmitted_jobs
106
Matthew Hartfb6fd362020-03-04 21:03:59 +0000107def fetch_artifacts(jobs, user_args, lava):
108 if not user_args.artifacts_path:
109 return
110 for job_id, info in jobs.items():
111 job_dir = info['job_dir']
112 info_print("Fetching artifacts for JOB: {} to {}".format(job_id, job_dir))
113 os.makedirs(job_dir, exist_ok=True)
114 def_path = os.path.join(job_dir, 'definition.yaml')
115 target_log = os.path.join(job_dir, 'target_log.txt')
Matthew Hart4a4f1202020-06-12 15:52:46 +0100116 config = os.path.join(job_dir, 'config.tar.bz2')
117 results_file = os.path.join(job_dir, 'results.yaml')
Matthew Hartfb6fd362020-03-04 21:03:59 +0000118 definition, metadata = lava.get_job_definition(job_id, def_path)
119 jobs[job_id]['metadata'] = metadata
120 time.sleep(0.2) # be friendly to LAVA
Matthew Hart4a4f1202020-06-12 15:52:46 +0100121 lava.get_job_log(job_id, target_log)
Matthew Hartfb6fd362020-03-04 21:03:59 +0000122 time.sleep(0.2)
123 lava.get_job_config(job_id, config)
124 time.sleep(0.2)
Matthew Hart4a4f1202020-06-12 15:52:46 +0100125 lava.get_job_results(job_id, results_file)
Matthew Hartfb6fd362020-03-04 21:03:59 +0000126 return(jobs)
127
128
129def lava_id_to_url(id, user_args):
130 return "{}/scheduler/job/{}".format(user_args.lava_url, id)
131
Xinyu Zhang1b8f5152020-11-13 16:10:58 +0800132def generateTestResult(info):
133 if info['health'] == "Complete" and info['state'] == "Finished":
134 return "PASS"
135 else:
136 return "FAIL"
137
Xinyu Zhang97ee3fd2020-12-14 14:45:06 +0800138def job_links(jobs, user_args):
139 job_links = ""
140 for job, info in jobs.items():
141 job_links += "Build Config: {} ".format(info['metadata']['build_name'])
142 job_links += "LAVA link: {} ".format(lava_id_to_url(job, user_args))
143 job_links += "Build link: {}\n".format(info['metadata']['build_job_url'])
144 print(job_links)
145
Xinyu Zhang1b8f5152020-11-13 16:10:58 +0800146def csv_report(jobs):
147 lava_jobs = []
148 for job, info in jobs.items():
149 exist = False
150 for record in lava_jobs:
151 if info['metadata']['platform'] == record["Platform"] and \
152 info['metadata']['compiler'] == record["Compiler"] and \
153 info['metadata']['build_type'] == record["Build Type"]:
154 if record[info['metadata']['name']] != "FAIL":
155 record[info['metadata']['name']] = generateTestResult(info)
156 exist = True
157 break
158 if not exist:
159 record = {}
160 record["Platform"] = info['metadata']['platform']
161 record["Compiler"] = info['metadata']['compiler']
162 record["Build Type"] = info['metadata']['build_type']
163 record["Config Name"] = info['metadata']['name']
164 for cfg in cfgs:
165 record[cfg] = "N.A."
166 record[info['metadata']['name']] = generateTestResult(info)
167 lava_jobs.append(record)
168 lava_jobs.sort(key=lambda x: x["Platform"] + x["Compiler"] + x["Build Type"])
169 with open("test_results.csv", "w", newline="") as csvfile:
170 fieldnames = ["Platform", "Compiler", "Build Type"] + cfgs
171 writer = csv.DictWriter(csvfile, fieldnames=fieldnames, extrasaction='ignore')
172
173 writer.writeheader()
174 writer.writerows(lava_jobs)
175
Matthew Hartfb6fd362020-03-04 21:03:59 +0000176def boot_report(jobs, user_args):
177 incomplete_jobs = []
178 for job, info in jobs.items():
179 if info['health'] != 'Complete':
180 if info['error_reason'] == 'Infrastructure':
181 info_print("Job {} failed with Infrastructure error".format(job))
182 incomplete_jobs.append(job)
183 incomplete_output = [lava_id_to_url(x, user_args) for x in incomplete_jobs];
184 if len(incomplete_jobs) > 0:
185 print("BOOT_RESULT: -1 Failed: {}".format(incomplete_output))
186 else:
187 print("BOOT_RESULT: +1")
188
Xinyu Zhang38a18872020-11-23 16:45:28 +0800189def failure_report(jobs, user_args):
190 failed_report = "FAILURE_TESTS:"
191 for job, info in jobs.items():
192 if info['health'] != "Complete" or info['state'] != "Finished":
193 failed_report += " {}:{}".format(info['metadata']['build_name'],
194 lava_id_to_url(job, user_args))
195 print(failed_report)
196
Matthew Hartfb6fd362020-03-04 21:03:59 +0000197def remove_lava_dupes(results):
198 for result in results:
199 if result['result'] != 'pass':
200 if result['suite'] == "lava":
201 for other in [x for x in results if x != result]:
202 if other['name'] == result['name']:
203 if other['result'] == 'pass':
204 results.remove(result)
205 return(results)
206
207def test_report(jobs, user_args, lava):
208 # parsing of test results is WIP
209 fail_j = []
210 jinja_data = []
211 for job, info in jobs.items():
Matthew Hart4a4f1202020-06-12 15:52:46 +0100212 results_file = os.path.join(info['job_dir'], 'results.yaml')
213 if not os.path.exists(results_file) or (os.path.getsize(results_file) == 0):
214 fail_j.append(job)
215 continue
216 with open(results_file, "r") as F:
217 res_data = F.read()
218 results = yaml.load(res_data)
Matthew Hartfb6fd362020-03-04 21:03:59 +0000219 non_lava_results = [x for x in results if x['suite'] != 'lava']
220 info['lava_url'] = lava_id_to_url(job, user_args)
221 info['artifacts_dir'] = "tf-m-ci-scripts/{}".format(info['job_dir'])
222 jinja_data.append({job: [info, non_lava_results]})
223 for result in non_lava_results:
224 if result['result'] != 'pass':
225 fail_j.append(job) if job not in fail_j else fail_j
226 time.sleep(0.5) # be friendly to LAVA
227 fail_output = [lava_id_to_url(x, user_args) for x in fail_j]
228 if len(fail_j) > 0:
229 print("TEST_RESULT: -1 Failed: {}".format(fail_output))
230 else:
231 print("TEST_RESULT: +1")
232 data = {}
233 data['jobs'] = jinja_data
234 render_jinja(data)
235
236def render_jinja(data):
237 work_dir = os.path.join(os.path.abspath(os.path.dirname(__file__)), "jinja2_templates")
238 template_loader = FileSystemLoader(searchpath=work_dir)
239 template_env = Environment(loader=template_loader)
240 html = template_env.get_template("test_summary.jinja2").render(data)
241 csv = template_env.get_template("test_summary_csv.jinja2").render(data)
242 with open('test_summary.html', "w") as F:
243 F.write(html)
244 with open('test_summary.csv', "w") as F:
245 F.write(csv)
246
247def print_lava_urls(jobs, user_args):
248 output = [lava_id_to_url(x, user_args) for x in jobs]
249 print("LAVA jobs triggered for this build: {}".format(output))
250
251
252def info_print(line):
253 print("INFO: {}".format(line))
254
255def main(user_args):
256 """ Main logic """
257 user_args.lava_rpc = "RPC2"
Xinyu Zhang3e8f6602021-04-28 10:57:32 +0800258 for try_time in range(3):
259 try:
260 wait_for_jobs(user_args)
261 break
262 except Exception as e:
263 print(e)
264 if try_time < 2:
265 print("Try to get LAVA jobs again...")
266 else:
267 raise e
Matthew Hartfb6fd362020-03-04 21:03:59 +0000268
269def get_cmd_args():
270 """ Parse command line arguments """
271
272 # Parse command line arguments to override config
273 parser = argparse.ArgumentParser(description="Lava Wait Jobs")
274 cmdargs = parser.add_argument_group("Lava Wait Jobs")
275
276 # Configuration control
277 cmdargs.add_argument(
278 "--lava-url", dest="lava_url", action="store", help="LAVA lab URL (without RPC2)"
279 )
280 cmdargs.add_argument(
281 "--job-ids", dest="job_ids", action="store", required=True, help="Comma separated list of job IDS"
282 )
283 cmdargs.add_argument(
Xinyu Zhangf2b7cbf2021-05-18 20:17:34 +0800284 "--lava-token", dest="lava_token", action="store", help="LAVA auth token"
Matthew Hartfb6fd362020-03-04 21:03:59 +0000285 )
286 cmdargs.add_argument(
Xinyu Zhangf2b7cbf2021-05-18 20:17:34 +0800287 "--lava-user", dest="lava_user", action="store", help="LAVA username"
Matthew Hartfb6fd362020-03-04 21:03:59 +0000288 )
289 cmdargs.add_argument(
290 "--use-env", dest="token_from_env", action="store_true", default=False, help="Use LAVA auth info from environment"
291 )
292 cmdargs.add_argument(
293 "--lava-timeout", dest="dispatch_timeout", action="store", type=int, default=3600, help="Time in seconds to wait for all jobs"
294 )
295 cmdargs.add_argument(
296 "--artifacts-path", dest="artifacts_path", action="store", help="Download LAVA artifacts to this directory"
297 )
298 return parser.parse_args()
299
300
301if __name__ == "__main__":
302 main(get_cmd_args())