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 | b97619c | 2022-08-01 18:07:35 +0800 | [diff] [blame] | 18 | types = ["ta", "vmxta", "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/") |
Bo Lv | 9edb699 | 2021-09-06 11:31:00 +0800 | [diff] [blame] | 111 | elif type == "bl31": |
Hangyu Li | b97619c | 2022-08-01 18:07:35 +0800 | [diff] [blame] | 112 | return urljoin(serverRootUrl, "Signing/job/Sign_Bl31/") |
Bo Lv | 9edb699 | 2021-09-06 11:31:00 +0800 | [diff] [blame] | 113 | elif type == "bl2": |
Hangyu Li | b97619c | 2022-08-01 18:07:35 +0800 | [diff] [blame] | 114 | return urljoin(serverRootUrl, "Signing/job/Sign_Bl2/") |
Bo Lv | 9edb699 | 2021-09-06 11:31:00 +0800 | [diff] [blame] | 115 | elif type == "bl32": |
Hangyu Li | b97619c | 2022-08-01 18:07:35 +0800 | [diff] [blame] | 116 | return urljoin(serverRootUrl, "Signing/job/Sign_Bl32/") |
Hangyu Li | 229ddee | 2022-03-24 13:57:51 +0800 | [diff] [blame] | 117 | elif type == "aucpufw": |
Hangyu Li | b97619c | 2022-08-01 18:07:35 +0800 | [diff] [blame] | 118 | return urljoin(serverRootUrl, "Signing/job/Sign_AUCPU_FW/") |
Hangyu Li | 22720d5 | 2022-03-29 11:07:20 +0800 | [diff] [blame] | 119 | elif type == "vdecfw": |
Hangyu Li | b97619c | 2022-08-01 18:07:35 +0800 | [diff] [blame] | 120 | return urljoin(serverRootUrl, "Signing/job/Sign_VDEC_FW/") |
Bo Lv | 9edb699 | 2021-09-06 11:31:00 +0800 | [diff] [blame] | 121 | else: # bl2e, bl2x, bl40 |
Hangyu Li | b97619c | 2022-08-01 18:07:35 +0800 | [diff] [blame] | 122 | return urljoin(serverRootUrl, "Signing/job/Sign_Bl2e_Bl2x_Bl40/") |
Bo Lv | 9edb699 | 2021-09-06 11:31:00 +0800 | [diff] [blame] | 123 | |
| 124 | |
| 125 | def getJobName(type): |
| 126 | if type == "ta": |
| 127 | return "Sign_TA" |
| 128 | elif type == "bl31": |
| 129 | return "Sign_Bl31" |
| 130 | elif type == "bl2": |
| 131 | return "Sign_Bl2" |
| 132 | elif type == "bl32": |
| 133 | return "Sign_Bl32" |
Hangyu Li | 229ddee | 2022-03-24 13:57:51 +0800 | [diff] [blame] | 134 | elif type == "aucpufw": |
| 135 | return "Sign_AUCPU_FW" |
Hangyu Li | 22720d5 | 2022-03-29 11:07:20 +0800 | [diff] [blame] | 136 | elif type == "vdecfw": |
| 137 | return "Sign_VDEC_FW" |
Bo Lv | 9edb699 | 2021-09-06 11:31:00 +0800 | [diff] [blame] | 138 | else: # bl2e, bl2x, bl40 |
| 139 | return "Sign_Bl2e_Bl2x_Bl40" |
| 140 | |
| 141 | |
| 142 | def submitSignJob( |
| 143 | type, |
| 144 | chipType, |
| 145 | inputFilePath, |
| 146 | chipAcsFilePath, |
| 147 | taVersion="0", |
Hangyu Li | 4d44bba | 2022-05-11 14:33:08 +0800 | [diff] [blame] | 148 | marketId="", |
Bo Lv | 9edb699 | 2021-09-06 11:31:00 +0800 | [diff] [blame] | 149 | casProvider="", |
| 150 | chipVariant="", |
| 151 | ddrType="", |
| 152 | keyType="dev-keys", |
Tao Zeng | 4c3f74e | 2021-09-26 14:09:13 +0800 | [diff] [blame] | 153 | extraArgs="", |
Pengguang Zhu | 899a8de | 2021-09-17 15:48:28 +0800 | [diff] [blame] | 154 | testService=0, |
Bo Lv | 9edb699 | 2021-09-06 11:31:00 +0800 | [diff] [blame] | 155 | ): |
| 156 | |
| 157 | fileName = os.path.basename(inputFilePath) |
| 158 | fileParameter = "file" |
| 159 | uploadFile = { |
| 160 | fileParameter: (fileName, open(inputFilePath, "rb")), |
| 161 | } |
| 162 | url = getJobRootUrl(type) + "buildWithParameters" |
| 163 | if type == "ta": |
| 164 | data = { |
| 165 | "chip_part_number": chipType, |
| 166 | "ta_version": taVersion, |
Hangyu Li | 4d44bba | 2022-05-11 14:33:08 +0800 | [diff] [blame] | 167 | "market_id": marketId, |
Pengguang Zhu | 899a8de | 2021-09-17 15:48:28 +0800 | [diff] [blame] | 168 | "testService": testService, |
Bo Lv | 9edb699 | 2021-09-06 11:31:00 +0800 | [diff] [blame] | 169 | } |
| 170 | elif type == "bl32": |
| 171 | |
| 172 | data = { |
| 173 | "chipPartNumber": chipType, |
| 174 | "casProvider": casProvider, |
| 175 | "keyType": keyType, |
Pengguang Zhu | 899a8de | 2021-09-17 15:48:28 +0800 | [diff] [blame] | 176 | "testService": testService, |
Bo Lv | 9edb699 | 2021-09-06 11:31:00 +0800 | [diff] [blame] | 177 | } |
| 178 | |
| 179 | elif type == "bl2": |
| 180 | chipAcsfileName = os.path.basename(chipAcsFilePath) |
| 181 | uploadFile = { |
| 182 | fileParameter: (fileName, open(inputFilePath, "rb")), |
| 183 | "chipAcsFile": (chipAcsfileName, open(chipAcsFilePath, "rb")), |
| 184 | } |
| 185 | data = { |
| 186 | "chipPartNumber": chipType, |
| 187 | "chipVariant": chipVariant, |
| 188 | "ddrType": ddrType, |
| 189 | "keyType": keyType, |
Pengguang Zhu | 899a8de | 2021-09-17 15:48:28 +0800 | [diff] [blame] | 190 | "testService": testService, |
Bo Lv | 9edb699 | 2021-09-06 11:31:00 +0800 | [diff] [blame] | 191 | } |
Hangyu Li | 22720d5 | 2022-03-29 11:07:20 +0800 | [diff] [blame] | 192 | else: # bl2e, bl2x, bl31, bl40, aucpufw, vdecfw |
Pengguang Zhu | 899a8de | 2021-09-17 15:48:28 +0800 | [diff] [blame] | 193 | data = { |
| 194 | "chipPartNumber": chipType, |
| 195 | "keyType": keyType, |
Tao Zeng | 4c3f74e | 2021-09-26 14:09:13 +0800 | [diff] [blame] | 196 | "extraArgs": extraArgs, |
Pengguang Zhu | 899a8de | 2021-09-17 15:48:28 +0800 | [diff] [blame] | 197 | "testService": testService, |
| 198 | } |
Bo Lv | 9edb699 | 2021-09-06 11:31:00 +0800 | [diff] [blame] | 199 | |
| 200 | response = requests.post(url, auth=auth, data=data, files=uploadFile) |
| 201 | |
| 202 | if response.status_code == 201: |
| 203 | print("Sumbit signing job successfully, please wait...") |
| 204 | |
| 205 | else: |
| 206 | print( |
| 207 | "Fail to start signing job due to the error: " + str(response.status_code) |
| 208 | ) |
| 209 | exit(1) |
| 210 | |
| 211 | |
| 212 | def queryBuildStatus(rootJobUrl, buildNumber): |
| 213 | url = rootJobUrl + str(buildNumber) + "/api/json?tree=building" |
| 214 | |
| 215 | response = requests.get(url, auth=auth) |
| 216 | |
| 217 | if response.status_code == 200: |
| 218 | result = json.loads(response.text) |
| 219 | return str(result["building"]) |
| 220 | else: |
| 221 | return "NotStart" |
| 222 | |
| 223 | |
| 224 | def downloadSignedFile(rootJobUrl, buildNumber, inFileDir="", specifiedOutFilePath=""): |
| 225 | |
| 226 | url = rootJobUrl + str(buildNumber) + "/api/json?tree=artifacts[relativePath]" |
| 227 | |
| 228 | response = requests.get(url, auth=auth) |
| 229 | |
| 230 | if response.status_code == 200: |
| 231 | result = json.loads(response.text) |
| 232 | if len(result["artifacts"]) == 0: |
| 233 | print("Fail to build, please check jenkins log for detailed error") |
| 234 | exit(1) |
| 235 | relativePath = result["artifacts"][0]["relativePath"] |
| 236 | # http://127.0.0.1:8080/job/Sign_Bl31/46/artifact/46/output/bl31-payload.bin.signed |
| 237 | downloadUrl = rootJobUrl + str(buildNumber) + "/artifact/" + "/" + relativePath |
| 238 | if specifiedOutFilePath == "": |
| 239 | outFilePath = os.path.join(inFileDir, os.path.basename(relativePath)) |
| 240 | else: |
| 241 | outFilePath = specifiedOutFilePath |
| 242 | r = requests.get(downloadUrl, auth=auth) |
| 243 | with open(outFilePath, "wb") as f: |
| 244 | f.write(r.content) |
| 245 | print("Download the signed file at " + outFilePath) |
| 246 | return 0 |
| 247 | else: |
| 248 | print("Fail to download the signed file") |
| 249 | exit(1) |
| 250 | return 1 |
| 251 | |
| 252 | |
| 253 | def waitForSubmit(type): |
| 254 | jobName = getJobName(type) |
| 255 | |
| 256 | while True: |
| 257 | queues = server.get_queue_info() |
| 258 | inQueue = False |
| 259 | if queues: |
| 260 | for queue_job_info in queues: |
| 261 | if queue_job_info["task"].get("name", "") == jobName: |
| 262 | inQueue = True |
| 263 | break |
| 264 | if inQueue: |
| 265 | time.sleep(1) |
| 266 | print( |
| 267 | "Otherone is signing same firmware as you request. Please wait them to complete." |
| 268 | ) |
| 269 | else: |
| 270 | print("It is your turn to submit your signing job now.") |
| 271 | break |
| 272 | |
| 273 | |
| 274 | def main(): |
| 275 | print(sys.argv) |
| 276 | init() |
| 277 | args = get_args() |
| 278 | |
| 279 | rootJobUrl = getJobRootUrl(args.type) |
| 280 | |
| 281 | waitForSubmit(args.type) |
| 282 | lastBuildNumber = getLastBuildNumber(rootJobUrl) |
| 283 | submitSignJob( |
| 284 | type=args.type, |
| 285 | chipType=args.chip, |
| 286 | inputFilePath=args.inputFilePath, |
| 287 | chipAcsFilePath=args.chipAcsFilePath, |
| 288 | taVersion=args.taVersion, |
Hangyu Li | 4d44bba | 2022-05-11 14:33:08 +0800 | [diff] [blame] | 289 | marketId=args.marketId, |
Bo Lv | 9edb699 | 2021-09-06 11:31:00 +0800 | [diff] [blame] | 290 | casProvider=args.casProvider, |
| 291 | chipVariant=args.chipVariant, |
| 292 | ddrType=args.ddrType, |
| 293 | keyType=args.keyType, |
Tao Zeng | 4c3f74e | 2021-09-26 14:09:13 +0800 | [diff] [blame] | 294 | extraArgs=args.extraArgs, |
Pengguang Zhu | 899a8de | 2021-09-17 15:48:28 +0800 | [diff] [blame] | 295 | testService=args.testService, |
Bo Lv | 9edb699 | 2021-09-06 11:31:00 +0800 | [diff] [blame] | 296 | ) |
| 297 | |
| 298 | buildNumber = int(lastBuildNumber) + 1 |
| 299 | print("The jenkins build number: " + str(buildNumber)) |
| 300 | while True: |
| 301 | time.sleep(1) |
| 302 | building = queryBuildStatus(rootJobUrl, buildNumber) |
| 303 | print("Building Status= " + str(building)) |
| 304 | if building == "False": |
| 305 | print("Build is done. Will start to download the signed file") |
| 306 | break |
| 307 | inputFileDir = os.path.dirname(args.inputFilePath) |
| 308 | downloadSignedFile(rootJobUrl, buildNumber, inputFileDir, args.outFilePath) |
| 309 | |
| 310 | |
| 311 | if __name__ == "__main__": |
| 312 | main() |