blob: 039af30a003df87db5a0e16b6a4cdd19e49c8680 [file] [log] [blame]
Bo Lv9edb6992021-09-06 11:31:00 +08001#!/usr/bin/env python3
2
3import sys
4import os
5import re
6import requests
7from requests.auth import HTTPBasicAuth
8from urllib.parse import urljoin
9import urllib.request
10import json
11import time
12from os.path import expanduser
13import jenkins
14
15
Hangyu Lib97619c2022-08-01 18:07:35 +080016serverRootUrl = "https://jenkins-sh.amlogic.com/job/Security/job/"
Bo Lv9edb6992021-09-06 11:31:00 +080017homeConfigFilePath = "~/.sign.cfg"
Hangyu Lib97619c2022-08-01 18:07:35 +080018types = ["ta", "vmxta", "bl32", "bl31", "bl2", "bl2e", "bl2x", "bl40", "aucpufw", "vdecfw"]
Hangyu Li0d2e7052022-11-02 15:26:11 +080019casProviders = ["", "VMX", "nagra", "nagra-dev", "vo-dev", "vo", "gs-dev", "gs", "irdeto"]
Bo Lv9edb6992021-09-06 11:31:00 +080020ddrTypes = ["ddr4", "lpddr4", "ddr3", "lpddr3", "lpddr4_lpddr5"]
21chipVariants = ["general", "nocs-jts-ap", "nocs-prod"]
22
23user = ""
24password = ""
25auth = None
26server = None
27
28
29def 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
62def 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 Li4d44bba2022-05-11 14:33:08 +080080 parser.add_argument("--marketId", type=str, default="null")
Bo Lv9edb6992021-09-06 11:31:00 +080081 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 Zeng4c3f74e2021-09-26 14:09:13 +080085 parser.add_argument("--extraArgs", type=str, default="")
Pengguang Zhu899a8de2021-09-17 15:48:28 +080086 parser.add_argument("--testService", type=int, default=0)
Bo Lv9edb6992021-09-06 11:31:00 +080087
88 return parser.parse_args()
89
90
91def 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
106def getJobRootUrl(type):
107 if type == "ta":
Hangyu Lib97619c2022-08-01 18:07:35 +0800108 return urljoin(serverRootUrl, "Signing/job/Sign_TA/")
109 elif type == "vmxta":
110 return urljoin(serverRootUrl, "CAS/job/VMX/job/VMX_TA_Sign/")
Bo Lv9edb6992021-09-06 11:31:00 +0800111 elif type == "bl31":
Hangyu Lib97619c2022-08-01 18:07:35 +0800112 return urljoin(serverRootUrl, "Signing/job/Sign_Bl31/")
Bo Lv9edb6992021-09-06 11:31:00 +0800113 elif type == "bl2":
Hangyu Lib97619c2022-08-01 18:07:35 +0800114 return urljoin(serverRootUrl, "Signing/job/Sign_Bl2/")
Bo Lv9edb6992021-09-06 11:31:00 +0800115 elif type == "bl32":
Hangyu Lib97619c2022-08-01 18:07:35 +0800116 return urljoin(serverRootUrl, "Signing/job/Sign_Bl32/")
Hangyu Li229ddee2022-03-24 13:57:51 +0800117 elif type == "aucpufw":
Hangyu Lib97619c2022-08-01 18:07:35 +0800118 return urljoin(serverRootUrl, "Signing/job/Sign_AUCPU_FW/")
Hangyu Li22720d52022-03-29 11:07:20 +0800119 elif type == "vdecfw":
Hangyu Lib97619c2022-08-01 18:07:35 +0800120 return urljoin(serverRootUrl, "Signing/job/Sign_VDEC_FW/")
Bo Lv9edb6992021-09-06 11:31:00 +0800121 else: # bl2e, bl2x, bl40
Hangyu Lib97619c2022-08-01 18:07:35 +0800122 return urljoin(serverRootUrl, "Signing/job/Sign_Bl2e_Bl2x_Bl40/")
Bo Lv9edb6992021-09-06 11:31:00 +0800123
124
125def 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 Li229ddee2022-03-24 13:57:51 +0800134 elif type == "aucpufw":
135 return "Sign_AUCPU_FW"
Hangyu Li22720d52022-03-29 11:07:20 +0800136 elif type == "vdecfw":
137 return "Sign_VDEC_FW"
Bo Lv9edb6992021-09-06 11:31:00 +0800138 else: # bl2e, bl2x, bl40
139 return "Sign_Bl2e_Bl2x_Bl40"
140
141
142def submitSignJob(
143 type,
144 chipType,
145 inputFilePath,
146 chipAcsFilePath,
147 taVersion="0",
Hangyu Li4d44bba2022-05-11 14:33:08 +0800148 marketId="",
Bo Lv9edb6992021-09-06 11:31:00 +0800149 casProvider="",
150 chipVariant="",
151 ddrType="",
152 keyType="dev-keys",
Tao Zeng4c3f74e2021-09-26 14:09:13 +0800153 extraArgs="",
Pengguang Zhu899a8de2021-09-17 15:48:28 +0800154 testService=0,
Bo Lv9edb6992021-09-06 11:31:00 +0800155):
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 Li4d44bba2022-05-11 14:33:08 +0800167 "market_id": marketId,
Pengguang Zhu899a8de2021-09-17 15:48:28 +0800168 "testService": testService,
Bo Lv9edb6992021-09-06 11:31:00 +0800169 }
170 elif type == "bl32":
171
172 data = {
173 "chipPartNumber": chipType,
174 "casProvider": casProvider,
175 "keyType": keyType,
Pengguang Zhu899a8de2021-09-17 15:48:28 +0800176 "testService": testService,
Bo Lv9edb6992021-09-06 11:31:00 +0800177 }
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 Zhu899a8de2021-09-17 15:48:28 +0800190 "testService": testService,
Bo Lv9edb6992021-09-06 11:31:00 +0800191 }
Hangyu Li22720d52022-03-29 11:07:20 +0800192 else: # bl2e, bl2x, bl31, bl40, aucpufw, vdecfw
Pengguang Zhu899a8de2021-09-17 15:48:28 +0800193 data = {
194 "chipPartNumber": chipType,
195 "keyType": keyType,
Tao Zeng4c3f74e2021-09-26 14:09:13 +0800196 "extraArgs": extraArgs,
Pengguang Zhu899a8de2021-09-17 15:48:28 +0800197 "testService": testService,
198 }
Bo Lv9edb6992021-09-06 11:31:00 +0800199
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
212def 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
224def 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
253def 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
274def 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 Li4d44bba2022-05-11 14:33:08 +0800289 marketId=args.marketId,
Bo Lv9edb6992021-09-06 11:31:00 +0800290 casProvider=args.casProvider,
291 chipVariant=args.chipVariant,
292 ddrType=args.ddrType,
293 keyType=args.keyType,
Tao Zeng4c3f74e2021-09-26 14:09:13 +0800294 extraArgs=args.extraArgs,
Pengguang Zhu899a8de2021-09-17 15:48:28 +0800295 testService=args.testService,
Bo Lv9edb6992021-09-06 11:31:00 +0800296 )
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
311if __name__ == "__main__":
312 main()