Matthew Hart | fb6fd36 | 2020-03-04 21:03:59 +0000 | [diff] [blame] | 1 | #!/usr/bin/env python3 |
| 2 | |
| 3 | from __future__ import print_function |
| 4 | |
| 5 | __copyright__ = """ |
| 6 | /* |
Xinyu Zhang | 28d61b4 | 2022-03-21 16:46:35 +0800 | [diff] [blame^] | 7 | * Copyright (c) 2020-2022, Arm Limited. All rights reserved. |
Matthew Hart | fb6fd36 | 2020-03-04 21:03:59 +0000 | [diff] [blame] | 8 | * |
| 9 | * SPDX-License-Identifier: BSD-3-Clause |
| 10 | * |
| 11 | */ |
| 12 | """ |
| 13 | |
| 14 | """ |
Fathi Boudra | 13b7eba | 2020-11-26 10:29:53 +0100 | [diff] [blame] | 15 | Script to create LAVA definitions from a single tf-m-build-config Jenkins Job |
Matthew Hart | fb6fd36 | 2020-03-04 21:03:59 +0000 | [diff] [blame] | 16 | """ |
| 17 | |
| 18 | import os |
| 19 | import sys |
Matthew Hart | fb6fd36 | 2020-03-04 21:03:59 +0000 | [diff] [blame] | 20 | import argparse |
Matthew Hart | fb6fd36 | 2020-03-04 21:03:59 +0000 | [diff] [blame] | 21 | from jinja2 import Environment, FileSystemLoader |
| 22 | from lava_helper_configs import * |
| 23 | |
| 24 | try: |
| 25 | from tfm_ci_pylib.lava_rpc_connector import LAVA_RPC_connector |
| 26 | except ImportError: |
| 27 | dir_path = os.path.dirname(os.path.realpath(__file__)) |
| 28 | sys.path.append(os.path.join(dir_path, "../")) |
| 29 | from tfm_ci_pylib.lava_rpc_connector import LAVA_RPC_connector |
| 30 | |
| 31 | |
| 32 | def load_config_overrides(user_args, config_key): |
Fathi Boudra | 13b7eba | 2020-11-26 10:29:53 +0100 | [diff] [blame] | 33 | """Load a configuration from multiple locations and override it with user provided |
| 34 | arguments""" |
Matthew Hart | fb6fd36 | 2020-03-04 21:03:59 +0000 | [diff] [blame] | 35 | |
| 36 | print("Using built-in config: %s" % config_key) |
| 37 | try: |
| 38 | config = lava_gen_config_map[config_key] |
| 39 | except KeyError: |
| 40 | print("No template found for config: %s" % config_key) |
| 41 | sys.exit(1) |
| 42 | |
| 43 | config["build_no"] = user_args.build_no |
Dean Birch | 5d2dc57 | 2020-05-29 13:15:59 +0100 | [diff] [blame] | 44 | config["artifact_store_url"] = user_args.jenkins_build_url |
Matthew Hart | fb6fd36 | 2020-03-04 21:03:59 +0000 | [diff] [blame] | 45 | |
Fathi Boudra | 13b7eba | 2020-11-26 10:29:53 +0100 | [diff] [blame] | 46 | # Add the template folder |
Matthew Hart | fb6fd36 | 2020-03-04 21:03:59 +0000 | [diff] [blame] | 47 | config["templ"] = os.path.join(user_args.template_dir, config["templ"]) |
| 48 | return config |
| 49 | |
| 50 | |
| 51 | def get_artifact_url(artifact_store_url, params, filename): |
Fathi Boudra | e9accbc | 2020-11-25 10:32:31 +0100 | [diff] [blame] | 52 | platform = params["platform"] |
| 53 | if params["device_type"] == "fvp": |
| 54 | platform = "fvp" |
| 55 | |
Fathi Boudra | caa90bd | 2020-12-04 22:00:14 +0100 | [diff] [blame] | 56 | url = "{}/artifact/trusted-firmware-m/build/bin/{}".format(artifact_store_url.rstrip("/"), filename) |
Fathi Boudra | e9accbc | 2020-11-25 10:32:31 +0100 | [diff] [blame] | 57 | return url |
Matthew Hart | fb6fd36 | 2020-03-04 21:03:59 +0000 | [diff] [blame] | 58 | |
| 59 | |
| 60 | def get_recovery_url(recovery_store_url, recovery): |
Dean Birch | 5d2dc57 | 2020-05-29 13:15:59 +0100 | [diff] [blame] | 61 | return "{}/{}".format(recovery_store_url.rstrip('/'), recovery) |
Matthew Hart | fb6fd36 | 2020-03-04 21:03:59 +0000 | [diff] [blame] | 62 | |
| 63 | |
| 64 | def get_job_name(name, params, job): |
| 65 | return "{}_{}_{}_{}_{}_{}_{}_{}".format( |
| 66 | name, |
| 67 | job, |
| 68 | params["platform"], |
| 69 | params["build_no"], |
| 70 | params["compiler"], |
| 71 | params["build_type"], |
| 72 | params["boot_type"], |
| 73 | params["name"], |
| 74 | ) |
| 75 | |
| 76 | |
| 77 | def get_build_name(params): |
| 78 | return "{}_{}_{}_{}_{}".format( |
| 79 | params["platform"], |
| 80 | params["compiler"], |
| 81 | params["name"], |
| 82 | params["build_type"], |
| 83 | params["boot_type"], |
| 84 | ) |
| 85 | |
| 86 | |
| 87 | def generate_test_definitions(config, work_dir, user_args): |
Fathi Boudra | 13b7eba | 2020-11-26 10:29:53 +0100 | [diff] [blame] | 88 | """Get a dictionary configuration and an existing jinja2 template to generate |
| 89 | a LAVA compatible yaml definition""" |
Matthew Hart | fb6fd36 | 2020-03-04 21:03:59 +0000 | [diff] [blame] | 90 | |
| 91 | template_loader = FileSystemLoader(searchpath=work_dir) |
| 92 | template_env = Environment(loader=template_loader) |
Dean Birch | 5d2dc57 | 2020-05-29 13:15:59 +0100 | [diff] [blame] | 93 | recovery_store_url = config.get('recovery_store_url', '') |
Matthew Hart | fb6fd36 | 2020-03-04 21:03:59 +0000 | [diff] [blame] | 94 | build_no = user_args.build_no |
Dean Birch | 5d2dc57 | 2020-05-29 13:15:59 +0100 | [diff] [blame] | 95 | artifact_store_url = config["artifact_store_url"] |
Matthew Hart | fb6fd36 | 2020-03-04 21:03:59 +0000 | [diff] [blame] | 96 | template_file = config.pop("templ") |
| 97 | |
| 98 | definitions = {} |
| 99 | |
| 100 | for platform, recovery in config["platforms"].items(): |
| 101 | if platform != user_args.platform: |
| 102 | continue |
| 103 | recovery_image_url = get_recovery_url(recovery_store_url, recovery) |
| 104 | for compiler in config["compilers"]: |
| 105 | if compiler != user_args.compiler: |
| 106 | continue |
| 107 | for build_type in config["build_types"]: |
| 108 | if build_type != user_args.build_type: |
| 109 | continue |
| 110 | for boot_type in config["boot_types"]: |
| 111 | bl2_string = "BL2" if user_args.bl2 else "NOBL2" |
| 112 | if boot_type != bl2_string: |
| 113 | continue |
| 114 | for test_name, test_dict in config["tests"].items(): |
| 115 | if "Config{}".format(test_name) != user_args.proj_config: |
| 116 | continue |
| 117 | params = { |
| 118 | "device_type": config["device_type"], |
| 119 | "job_timeout": config["job_timeout"], |
Fathi Boudra | 7454c55 | 2020-11-25 13:40:28 +0100 | [diff] [blame] | 120 | "action_timeout": config.get("action_timeout", ''), |
| 121 | "monitor_timeout": config.get("monitor_timeout", ''), |
| 122 | "poweroff_timeout": config.get("poweroff_timeout", ''), |
Matthew Hart | fb6fd36 | 2020-03-04 21:03:59 +0000 | [diff] [blame] | 123 | "compiler": compiler, |
| 124 | "build_type": build_type, |
| 125 | "build_no": build_no, |
| 126 | "boot_type": boot_type, |
| 127 | "name": test_name, |
| 128 | "test": test_dict, |
| 129 | "platform": platform, |
| 130 | "recovery_image_url": recovery_image_url, |
| 131 | "data_bin_offset": config.get('data_bin_offset', ''), |
| 132 | "docker_prefix": vars(user_args).get('docker_prefix', ''), |
| 133 | "license_variable": vars(user_args).get('license_variable', ''), |
Leonardo Sandoval | 66386a2 | 2021-04-15 14:35:08 -0500 | [diff] [blame] | 134 | "enable_code_coverage": user_args.enable_code_coverage == "TRUE", |
| 135 | "coverage_trace_plugin": coverage_trace_plugin, |
Matthew Hart | fb6fd36 | 2020-03-04 21:03:59 +0000 | [diff] [blame] | 136 | "build_job_url": artifact_store_url, |
Matthew Hart | 2c2688f | 2020-05-26 13:09:20 +0100 | [diff] [blame] | 137 | "cpu0_baseline": config.get("cpu0_baseline", 0), |
| 138 | "cpu0_initvtor_s": config.get("cpu0_initvtor_s", "0x10000000") |
Matthew Hart | fb6fd36 | 2020-03-04 21:03:59 +0000 | [diff] [blame] | 139 | } |
Xinyu Zhang | 28d61b4 | 2022-03-21 16:46:35 +0800 | [diff] [blame^] | 140 | for binary_type, binary_name in config["binaries"].items(): |
| 141 | params.update( |
| 142 | { |
| 143 | "{}_url".format(binary_type): get_artifact_url( |
| 144 | artifact_store_url, |
| 145 | params, |
| 146 | binary_name |
| 147 | ) |
| 148 | } |
| 149 | ) |
Matthew Hart | fb6fd36 | 2020-03-04 21:03:59 +0000 | [diff] [blame] | 150 | params.update( |
| 151 | { |
| 152 | "job_name": get_job_name( |
| 153 | config["job_name"], params, user_args.jenkins_job, |
| 154 | ), |
| 155 | "build_name": get_build_name(params) |
| 156 | } |
| 157 | ) |
| 158 | |
| 159 | definition = template_env.get_template(template_file).render( |
| 160 | params |
| 161 | ) |
| 162 | definitions.update({params["job_name"]: definition}) |
| 163 | return definitions |
| 164 | |
| 165 | |
| 166 | def generate_lava_job_defs(user_args, config): |
Fathi Boudra | 13b7eba | 2020-11-26 10:29:53 +0100 | [diff] [blame] | 167 | """Create a LAVA test job definition file""" |
Matthew Hart | fb6fd36 | 2020-03-04 21:03:59 +0000 | [diff] [blame] | 168 | |
| 169 | # Evaluate current directory |
| 170 | work_dir = os.path.abspath(os.path.dirname(__file__)) |
| 171 | |
| 172 | # If a single platform is requested and it exists in the platform |
| 173 | if user_args.platform and user_args.platform in config["platforms"]: |
| 174 | # Only test this platform |
| 175 | platform = user_args.platform |
| 176 | config["platforms"] = {platform: config["platforms"][platform]} |
Fathi Boudra | 13b7eba | 2020-11-26 10:29:53 +0100 | [diff] [blame] | 177 | # Generate the output definition |
Matthew Hart | fb6fd36 | 2020-03-04 21:03:59 +0000 | [diff] [blame] | 178 | definitions = generate_test_definitions(config, work_dir, user_args) |
Matthew Hart | fb6fd36 | 2020-03-04 21:03:59 +0000 | [diff] [blame] | 179 | # Write it into a file |
| 180 | out_dir = os.path.abspath(user_args.lava_def_output) |
| 181 | os.makedirs(out_dir, exist_ok=True) |
| 182 | for name, definition in definitions.items(): |
| 183 | out_file = os.path.join(out_dir, "{}{}".format(name, ".yaml")) |
| 184 | with open(out_file, "w") as F: |
| 185 | F.write(definition) |
| 186 | print("Definition created at %s" % out_file) |
| 187 | |
| 188 | |
| 189 | def main(user_args): |
| 190 | user_args.template_dir = "jinja2_templates" |
Xinyu Zhang | be224f6 | 2021-02-03 17:57:38 +0800 | [diff] [blame] | 191 | config_keys = list(lava_gen_config_map.keys()) |
| 192 | if user_args.fvp_only: |
| 193 | for key in config_keys: |
| 194 | if "fvp" not in key: |
| 195 | config_keys.remove(key) |
Xinyu Zhang | 302b74d | 2021-11-03 14:53:44 +0800 | [diff] [blame] | 196 | if user_args.physical_board_only: |
| 197 | for key in config_keys: |
| 198 | if "fvp" in key or "qemu" in key: |
| 199 | config_keys.remove(key) |
Matthew Hart | fb6fd36 | 2020-03-04 21:03:59 +0000 | [diff] [blame] | 200 | if user_args.config_key: |
| 201 | config_keys = [user_args.config_key] |
| 202 | for config_key in config_keys: |
| 203 | config = load_config_overrides(user_args, config_key) |
| 204 | generate_lava_job_defs(user_args, config) |
| 205 | |
| 206 | |
| 207 | def get_cmd_args(): |
Fathi Boudra | 13b7eba | 2020-11-26 10:29:53 +0100 | [diff] [blame] | 208 | """Parse command line arguments""" |
Matthew Hart | fb6fd36 | 2020-03-04 21:03:59 +0000 | [diff] [blame] | 209 | |
| 210 | # Parse command line arguments to override config |
| 211 | parser = argparse.ArgumentParser(description="Lava Create Jobs") |
| 212 | cmdargs = parser.add_argument_group("Create LAVA Jobs") |
Xinyu Zhang | 302b74d | 2021-11-03 14:53:44 +0800 | [diff] [blame] | 213 | device_type = parser.add_mutually_exclusive_group() |
Matthew Hart | fb6fd36 | 2020-03-04 21:03:59 +0000 | [diff] [blame] | 214 | |
| 215 | # Configuration control |
| 216 | cmdargs.add_argument( |
| 217 | "--config-name", |
| 218 | dest="config_key", |
| 219 | action="store", |
| 220 | help="Select built-in configuration by name", |
| 221 | ) |
| 222 | cmdargs.add_argument( |
| 223 | "--build-number", |
| 224 | dest="build_no", |
| 225 | action="store", |
| 226 | default="lastSuccessfulBuild", |
| 227 | help="JENKINS Build number selector. " "Default: lastSuccessfulBuild", |
| 228 | ) |
| 229 | cmdargs.add_argument( |
| 230 | "--output-dir", |
| 231 | dest="lava_def_output", |
| 232 | action="store", |
| 233 | default="job_results", |
| 234 | help="Set LAVA compatible .yaml output file", |
| 235 | ) |
| 236 | cmdargs.add_argument( |
| 237 | "--platform", |
| 238 | dest="platform", |
| 239 | action="store", |
| 240 | help="Override platform.Only the provided one " "will be tested", |
| 241 | ) |
| 242 | cmdargs.add_argument( |
| 243 | "--compiler", |
| 244 | dest="compiler", |
| 245 | action="store", |
| 246 | help="Compiler to build definitions for", |
| 247 | ) |
| 248 | cmdargs.add_argument( |
| 249 | "--jenkins-build-url", |
| 250 | dest="jenkins_build_url", |
| 251 | action="store", |
| 252 | help="Set the Jenkins URL", |
| 253 | ) |
| 254 | cmdargs.add_argument( |
| 255 | "--jenkins-job", |
| 256 | dest="jenkins_job", |
| 257 | action="store", |
| 258 | default="tf-m-build-config", |
| 259 | help="Set the jenkins job name", |
| 260 | ) |
| 261 | cmdargs.add_argument( |
| 262 | "--proj-config", dest="proj_config", action="store", help="Proj config" |
| 263 | ) |
| 264 | cmdargs.add_argument( |
| 265 | "--build-type", dest="build_type", action="store", help="Build type" |
| 266 | ) |
| 267 | cmdargs.add_argument( |
| 268 | "--docker-prefix", dest="docker_prefix", action="store", help="Prefix string for the FVP docker registry location" |
| 269 | ) |
| 270 | cmdargs.add_argument( |
| 271 | "--license-variable", dest="license_variable", action="store", help="License string for Fastmodels" |
| 272 | ) |
Leonardo Sandoval | 66386a2 | 2021-04-15 14:35:08 -0500 | [diff] [blame] | 273 | cmdargs.add_argument( |
| 274 | "--enable-code-coverage", dest="enable_code_coverage", action="store", default="FALSE", help="Enable trace-base code coverage" |
| 275 | ) |
Matthew Hart | fb6fd36 | 2020-03-04 21:03:59 +0000 | [diff] [blame] | 276 | cmdargs.add_argument("--bl2", dest="bl2", action="store_true", help="BL2") |
Matthew Hart | 2c2688f | 2020-05-26 13:09:20 +0100 | [diff] [blame] | 277 | cmdargs.add_argument( |
| 278 | "--psa-api-suite", dest="psa_suite", action="store", help="PSA API Suite name" |
| 279 | ) |
Matthew Hart | fb6fd36 | 2020-03-04 21:03:59 +0000 | [diff] [blame] | 280 | |
Xinyu Zhang | 302b74d | 2021-11-03 14:53:44 +0800 | [diff] [blame] | 281 | device_type.add_argument( |
| 282 | "--fvp-only", |
| 283 | dest="fvp_only", |
| 284 | action="store_true", |
| 285 | help="Run test cases on FVP only", |
| 286 | ) |
| 287 | device_type.add_argument( |
| 288 | "--physical-board-only", |
| 289 | dest="physical_board_only", |
| 290 | action="store_true", |
| 291 | help="Run test cases on physical boards only", |
| 292 | ) |
| 293 | |
| 294 | return parser.parse_args() |
Matthew Hart | fb6fd36 | 2020-03-04 21:03:59 +0000 | [diff] [blame] | 295 | |
| 296 | if __name__ == "__main__": |
| 297 | main(get_cmd_args()) |