Bo Lv | 9edb699 | 2021-09-06 11:31:00 +0800 | [diff] [blame] | 1 | #!/usr/bin/env python3 |
| 2 | |
| 3 | import sys |
| 4 | import os |
| 5 | import re |
| 6 | import requests |
| 7 | from requests.auth import HTTPBasicAuth |
| 8 | from urllib.parse import urljoin |
| 9 | import urllib.request |
| 10 | import json |
| 11 | import time |
| 12 | from os.path import expanduser |
| 13 | import jenkins |
| 14 | |
| 15 | |
Hangyu Li | b97619c | 2022-08-01 18:07:35 +0800 | [diff] [blame] | 16 | serverRootUrl = "https://jenkins-sh.amlogic.com/job/Security/job/" |
Bo Lv | 9edb699 | 2021-09-06 11:31:00 +0800 | [diff] [blame] | 17 | homeConfigFilePath = "~/.sign.cfg" |
Hangyu Li | 505e5eb | 2023-03-28 15:54:19 +0800 | [diff] [blame^] | 18 | types = ["ta", "vmxta", "irdetota", "bl32", "bl31", "bl2", "bl2e", "bl2x", "bl40", "aucpufw", "vdecfw"] |
Hangyu Li | 0d2e705 | 2022-11-02 15:26:11 +0800 | [diff] [blame] | 19 | casProviders = ["", "VMX", "nagra", "nagra-dev", "vo-dev", "vo", "gs-dev", "gs", "irdeto"] |
Bo Lv | 9edb699 | 2021-09-06 11:31:00 +0800 | [diff] [blame] | 20 | ddrTypes = ["ddr4", "lpddr4", "ddr3", "lpddr3", "lpddr4_lpddr5"] |
| 21 | chipVariants = ["general", "nocs-jts-ap", "nocs-prod"] |
| 22 | |
| 23 | user = "" |
| 24 | password = "" |
| 25 | auth = None |
| 26 | server = None |
| 27 | |
| 28 | |
| 29 | def init(): |
| 30 | global user |
| 31 | global password |
| 32 | global auth |
| 33 | global server |
| 34 | expandedHomeConfigFilePath = expanduser(homeConfigFilePath) |
| 35 | configPyPath = os.path.join(sys.path[0], "config.py") |
| 36 | if os.path.exists(expandedHomeConfigFilePath): |
| 37 | configFilePath = expandedHomeConfigFilePath |
| 38 | elif os.path.exists(configPyPath): |
| 39 | configFilePath = configPyPath |
| 40 | else: |
| 41 | print( |
| 42 | "Can't find configuration file. Please create configuration file .sign.cfg at your home directory." |
| 43 | ) |
| 44 | exit(1) |
| 45 | |
| 46 | with open(configFilePath, "r") as configFile: |
| 47 | while True: |
| 48 | line = configFile.readline() |
| 49 | if not line: |
| 50 | break |
| 51 | words = line.split("=") |
| 52 | if words[0].strip() == "user": |
| 53 | user = words[1].strip().replace("'", "") |
| 54 | elif words[0].strip() == "password": |
| 55 | password = words[1].strip().replace("'", "") |
| 56 | auth = HTTPBasicAuth(user, password) |
| 57 | server = jenkins.Jenkins( |
| 58 | "https://jenkins-sh.amlogic.com", username=user, password=password |
| 59 | ) |
| 60 | |
| 61 | |
| 62 | def get_args(): |
| 63 | from argparse import ArgumentParser |
| 64 | |
| 65 | parser = ArgumentParser() |
| 66 | |
| 67 | parser.add_argument("--in", dest="inputFilePath", required=True, help="input file") |
| 68 | parser.add_argument( |
| 69 | "--chipAcsFile", dest="chipAcsFilePath", default="null", help="chip acs file" |
| 70 | ) |
| 71 | parser.add_argument( |
| 72 | "--out", dest="outFilePath", type=str, default="", help="output signed file" |
| 73 | ) |
| 74 | parser.add_argument( |
| 75 | "-v", "--version", action="version", version="%(prog)s 1.0", help="version" |
| 76 | ) |
| 77 | parser.add_argument("--type", choices=types, default=types[0], required=True) |
| 78 | parser.add_argument("--chip", type=str) |
| 79 | parser.add_argument("--taVersion", type=int, default=0) |
Hangyu Li | 4d44bba | 2022-05-11 14:33:08 +0800 | [diff] [blame] | 80 | parser.add_argument("--marketId", type=str, default="null") |
Bo Lv | 9edb699 | 2021-09-06 11:31:00 +0800 | [diff] [blame] | 81 | parser.add_argument("--casProvider", choices=casProviders, default=casProviders[0]) |
| 82 | parser.add_argument("--ddrType", type=str, default=ddrTypes[0]) |
| 83 | parser.add_argument("--chipVariant", choices=chipVariants, default=chipVariants[0]) |
| 84 | parser.add_argument("--keyType", type=str, dest="keyType", default="dev-keys") |
Tao Zeng | 4c3f74e | 2021-09-26 14:09:13 +0800 | [diff] [blame] | 85 | parser.add_argument("--extraArgs", type=str, default="") |
Pengguang Zhu | 899a8de | 2021-09-17 15:48:28 +0800 | [diff] [blame] | 86 | parser.add_argument("--testService", type=int, default=0) |
Bo Lv | 9edb699 | 2021-09-06 11:31:00 +0800 | [diff] [blame] | 87 | |
| 88 | return parser.parse_args() |
| 89 | |
| 90 | |
| 91 | def getLastBuildNumber(rootJobUrl): |
| 92 | url = urljoin(rootJobUrl, "lastBuild/buildNumber") |
| 93 | |
| 94 | response = requests.get(url, auth=auth) |
| 95 | |
| 96 | if response.status_code == 200: |
| 97 | return response.text |
| 98 | else: |
| 99 | print( |
| 100 | "Fail to get last build number due to the error " |
| 101 | + str(response.status_code) |
| 102 | ) |
| 103 | return 0 |
| 104 | |
| 105 | |
| 106 | def getJobRootUrl(type): |
| 107 | if type == "ta": |
Hangyu Li | b97619c | 2022-08-01 18:07:35 +0800 | [diff] [blame] | 108 | return urljoin(serverRootUrl, "Signing/job/Sign_TA/") |
| 109 | elif type == "vmxta": |
| 110 | return urljoin(serverRootUrl, "CAS/job/VMX/job/VMX_TA_Sign/") |
Hangyu Li | 505e5eb | 2023-03-28 15:54:19 +0800 | [diff] [blame^] | 111 | elif type == "irdetota": |
| 112 | return urljoin(serverRootUrl, "Signing/job/Sign_Irdeto_TA_for_s905c1/") |
Bo Lv | 9edb699 | 2021-09-06 11:31:00 +0800 | [diff] [blame] | 113 | elif type == "bl31": |
Hangyu Li | b97619c | 2022-08-01 18:07:35 +0800 | [diff] [blame] | 114 | return urljoin(serverRootUrl, "Signing/job/Sign_Bl31/") |
Bo Lv | 9edb699 | 2021-09-06 11:31:00 +0800 | [diff] [blame] | 115 | elif type == "bl2": |
Hangyu Li | b97619c | 2022-08-01 18:07:35 +0800 | [diff] [blame] | 116 | return urljoin(serverRootUrl, "Signing/job/Sign_Bl2/") |
Bo Lv | 9edb699 | 2021-09-06 11:31:00 +0800 | [diff] [blame] | 117 | elif type == "bl32": |
Hangyu Li | b97619c | 2022-08-01 18:07:35 +0800 | [diff] [blame] | 118 | return urljoin(serverRootUrl, "Signing/job/Sign_Bl32/") |
Hangyu Li | 229ddee | 2022-03-24 13:57:51 +0800 | [diff] [blame] | 119 | elif type == "aucpufw": |
Hangyu Li | b97619c | 2022-08-01 18:07:35 +0800 | [diff] [blame] | 120 | return urljoin(serverRootUrl, "Signing/job/Sign_AUCPU_FW/") |
Hangyu Li | 22720d5 | 2022-03-29 11:07:20 +0800 | [diff] [blame] | 121 | elif type == "vdecfw": |
Hangyu Li | b97619c | 2022-08-01 18:07:35 +0800 | [diff] [blame] | 122 | return urljoin(serverRootUrl, "Signing/job/Sign_VDEC_FW/") |
Bo Lv | 9edb699 | 2021-09-06 11:31:00 +0800 | [diff] [blame] | 123 | else: # bl2e, bl2x, bl40 |
Hangyu Li | b97619c | 2022-08-01 18:07:35 +0800 | [diff] [blame] | 124 | return urljoin(serverRootUrl, "Signing/job/Sign_Bl2e_Bl2x_Bl40/") |
Bo Lv | 9edb699 | 2021-09-06 11:31:00 +0800 | [diff] [blame] | 125 | |
| 126 | |
| 127 | def getJobName(type): |
| 128 | if type == "ta": |
| 129 | return "Sign_TA" |
Hangyu Li | 505e5eb | 2023-03-28 15:54:19 +0800 | [diff] [blame^] | 130 | elif type == "vmxta": |
| 131 | return "Sign_VMX_TA" |
| 132 | elif type == "irdetota": |
| 133 | return "Sign_Irdeto_TA_for_s905c1" |
Bo Lv | 9edb699 | 2021-09-06 11:31:00 +0800 | [diff] [blame] | 134 | elif type == "bl31": |
| 135 | return "Sign_Bl31" |
| 136 | elif type == "bl2": |
| 137 | return "Sign_Bl2" |
| 138 | elif type == "bl32": |
| 139 | return "Sign_Bl32" |
Hangyu Li | 229ddee | 2022-03-24 13:57:51 +0800 | [diff] [blame] | 140 | elif type == "aucpufw": |
| 141 | return "Sign_AUCPU_FW" |
Hangyu Li | 22720d5 | 2022-03-29 11:07:20 +0800 | [diff] [blame] | 142 | elif type == "vdecfw": |
| 143 | return "Sign_VDEC_FW" |
Bo Lv | 9edb699 | 2021-09-06 11:31:00 +0800 | [diff] [blame] | 144 | else: # bl2e, bl2x, bl40 |
| 145 | return "Sign_Bl2e_Bl2x_Bl40" |
| 146 | |
| 147 | |
| 148 | def submitSignJob( |
| 149 | type, |
| 150 | chipType, |
| 151 | inputFilePath, |
| 152 | chipAcsFilePath, |
| 153 | taVersion="0", |
Hangyu Li | 4d44bba | 2022-05-11 14:33:08 +0800 | [diff] [blame] | 154 | marketId="", |
Bo Lv | 9edb699 | 2021-09-06 11:31:00 +0800 | [diff] [blame] | 155 | casProvider="", |
| 156 | chipVariant="", |
| 157 | ddrType="", |
| 158 | keyType="dev-keys", |
Tao Zeng | 4c3f74e | 2021-09-26 14:09:13 +0800 | [diff] [blame] | 159 | extraArgs="", |
Pengguang Zhu | 899a8de | 2021-09-17 15:48:28 +0800 | [diff] [blame] | 160 | testService=0, |
Bo Lv | 9edb699 | 2021-09-06 11:31:00 +0800 | [diff] [blame] | 161 | ): |
| 162 | |
| 163 | fileName = os.path.basename(inputFilePath) |
| 164 | fileParameter = "file" |
| 165 | uploadFile = { |
| 166 | fileParameter: (fileName, open(inputFilePath, "rb")), |
| 167 | } |
| 168 | url = getJobRootUrl(type) + "buildWithParameters" |
Hangyu Li | 505e5eb | 2023-03-28 15:54:19 +0800 | [diff] [blame^] | 169 | if type == "ta" or type == "vmxta" or type == "irdetota": |
Bo Lv | 9edb699 | 2021-09-06 11:31:00 +0800 | [diff] [blame] | 170 | data = { |
| 171 | "chip_part_number": chipType, |
| 172 | "ta_version": taVersion, |
Hangyu Li | 4d44bba | 2022-05-11 14:33:08 +0800 | [diff] [blame] | 173 | "market_id": marketId, |
Pengguang Zhu | 899a8de | 2021-09-17 15:48:28 +0800 | [diff] [blame] | 174 | "testService": testService, |
Bo Lv | 9edb699 | 2021-09-06 11:31:00 +0800 | [diff] [blame] | 175 | } |
| 176 | elif type == "bl32": |
| 177 | |
| 178 | data = { |
| 179 | "chipPartNumber": chipType, |
| 180 | "casProvider": casProvider, |
| 181 | "keyType": keyType, |
Pengguang Zhu | 899a8de | 2021-09-17 15:48:28 +0800 | [diff] [blame] | 182 | "testService": testService, |
Bo Lv | 9edb699 | 2021-09-06 11:31:00 +0800 | [diff] [blame] | 183 | } |
| 184 | |
| 185 | elif type == "bl2": |
| 186 | chipAcsfileName = os.path.basename(chipAcsFilePath) |
| 187 | uploadFile = { |
| 188 | fileParameter: (fileName, open(inputFilePath, "rb")), |
| 189 | "chipAcsFile": (chipAcsfileName, open(chipAcsFilePath, "rb")), |
| 190 | } |
| 191 | data = { |
| 192 | "chipPartNumber": chipType, |
| 193 | "chipVariant": chipVariant, |
| 194 | "ddrType": ddrType, |
| 195 | "keyType": keyType, |
Pengguang Zhu | 899a8de | 2021-09-17 15:48:28 +0800 | [diff] [blame] | 196 | "testService": testService, |
Bo Lv | 9edb699 | 2021-09-06 11:31:00 +0800 | [diff] [blame] | 197 | } |
Hangyu Li | 22720d5 | 2022-03-29 11:07:20 +0800 | [diff] [blame] | 198 | else: # bl2e, bl2x, bl31, bl40, aucpufw, vdecfw |
Pengguang Zhu | 899a8de | 2021-09-17 15:48:28 +0800 | [diff] [blame] | 199 | data = { |
| 200 | "chipPartNumber": chipType, |
| 201 | "keyType": keyType, |
Tao Zeng | 4c3f74e | 2021-09-26 14:09:13 +0800 | [diff] [blame] | 202 | "extraArgs": extraArgs, |
Pengguang Zhu | 899a8de | 2021-09-17 15:48:28 +0800 | [diff] [blame] | 203 | "testService": testService, |
| 204 | } |
Bo Lv | 9edb699 | 2021-09-06 11:31:00 +0800 | [diff] [blame] | 205 | |
| 206 | response = requests.post(url, auth=auth, data=data, files=uploadFile) |
| 207 | |
| 208 | if response.status_code == 201: |
| 209 | print("Sumbit signing job successfully, please wait...") |
| 210 | |
| 211 | else: |
| 212 | print( |
| 213 | "Fail to start signing job due to the error: " + str(response.status_code) |
| 214 | ) |
| 215 | exit(1) |
| 216 | |
| 217 | |
| 218 | def queryBuildStatus(rootJobUrl, buildNumber): |
| 219 | url = rootJobUrl + str(buildNumber) + "/api/json?tree=building" |
| 220 | |
| 221 | response = requests.get(url, auth=auth) |
| 222 | |
| 223 | if response.status_code == 200: |
| 224 | result = json.loads(response.text) |
| 225 | return str(result["building"]) |
| 226 | else: |
| 227 | return "NotStart" |
| 228 | |
| 229 | |
| 230 | def downloadSignedFile(rootJobUrl, buildNumber, inFileDir="", specifiedOutFilePath=""): |
| 231 | |
| 232 | url = rootJobUrl + str(buildNumber) + "/api/json?tree=artifacts[relativePath]" |
| 233 | |
| 234 | response = requests.get(url, auth=auth) |
| 235 | |
| 236 | if response.status_code == 200: |
| 237 | result = json.loads(response.text) |
| 238 | if len(result["artifacts"]) == 0: |
| 239 | print("Fail to build, please check jenkins log for detailed error") |
| 240 | exit(1) |
| 241 | relativePath = result["artifacts"][0]["relativePath"] |
| 242 | # http://127.0.0.1:8080/job/Sign_Bl31/46/artifact/46/output/bl31-payload.bin.signed |
| 243 | downloadUrl = rootJobUrl + str(buildNumber) + "/artifact/" + "/" + relativePath |
| 244 | if specifiedOutFilePath == "": |
| 245 | outFilePath = os.path.join(inFileDir, os.path.basename(relativePath)) |
| 246 | else: |
| 247 | outFilePath = specifiedOutFilePath |
| 248 | r = requests.get(downloadUrl, auth=auth) |
| 249 | with open(outFilePath, "wb") as f: |
| 250 | f.write(r.content) |
| 251 | print("Download the signed file at " + outFilePath) |
| 252 | return 0 |
| 253 | else: |
| 254 | print("Fail to download the signed file") |
| 255 | exit(1) |
| 256 | return 1 |
| 257 | |
| 258 | |
| 259 | def waitForSubmit(type): |
| 260 | jobName = getJobName(type) |
| 261 | |
| 262 | while True: |
| 263 | queues = server.get_queue_info() |
| 264 | inQueue = False |
| 265 | if queues: |
| 266 | for queue_job_info in queues: |
| 267 | if queue_job_info["task"].get("name", "") == jobName: |
| 268 | inQueue = True |
| 269 | break |
| 270 | if inQueue: |
| 271 | time.sleep(1) |
| 272 | print( |
| 273 | "Otherone is signing same firmware as you request. Please wait them to complete." |
| 274 | ) |
| 275 | else: |
| 276 | print("It is your turn to submit your signing job now.") |
| 277 | break |
| 278 | |
| 279 | |
| 280 | def main(): |
| 281 | print(sys.argv) |
| 282 | init() |
| 283 | args = get_args() |
| 284 | |
| 285 | rootJobUrl = getJobRootUrl(args.type) |
| 286 | |
| 287 | waitForSubmit(args.type) |
| 288 | lastBuildNumber = getLastBuildNumber(rootJobUrl) |
| 289 | submitSignJob( |
| 290 | type=args.type, |
| 291 | chipType=args.chip, |
| 292 | inputFilePath=args.inputFilePath, |
| 293 | chipAcsFilePath=args.chipAcsFilePath, |
| 294 | taVersion=args.taVersion, |
Hangyu Li | 4d44bba | 2022-05-11 14:33:08 +0800 | [diff] [blame] | 295 | marketId=args.marketId, |
Bo Lv | 9edb699 | 2021-09-06 11:31:00 +0800 | [diff] [blame] | 296 | casProvider=args.casProvider, |
| 297 | chipVariant=args.chipVariant, |
| 298 | ddrType=args.ddrType, |
| 299 | keyType=args.keyType, |
Tao Zeng | 4c3f74e | 2021-09-26 14:09:13 +0800 | [diff] [blame] | 300 | extraArgs=args.extraArgs, |
Pengguang Zhu | 899a8de | 2021-09-17 15:48:28 +0800 | [diff] [blame] | 301 | testService=args.testService, |
Bo Lv | 9edb699 | 2021-09-06 11:31:00 +0800 | [diff] [blame] | 302 | ) |
| 303 | |
| 304 | buildNumber = int(lastBuildNumber) + 1 |
| 305 | print("The jenkins build number: " + str(buildNumber)) |
| 306 | while True: |
| 307 | time.sleep(1) |
| 308 | building = queryBuildStatus(rootJobUrl, buildNumber) |
| 309 | print("Building Status= " + str(building)) |
| 310 | if building == "False": |
| 311 | print("Build is done. Will start to download the signed file") |
| 312 | break |
| 313 | inputFileDir = os.path.dirname(args.inputFilePath) |
| 314 | downloadSignedFile(rootJobUrl, buildNumber, inputFileDir, args.outFilePath) |
| 315 | |
| 316 | |
| 317 | if __name__ == "__main__": |
| 318 | main() |