1#-*- coding:utf-8 -*- 2import uuid 3import sys 4import subprocess 5import os 6import serial 7 8from core.base import BaseApp, dec_stepmsg 9from util.file_locker import FileLock 10from util.log_info import logger 11from util.time_info import get_now_time_str_info, get_now_time_info, Timeout, timeout 12from aw.Telnet.TelnetClient import TelConnect 13from aw.Common.Constant import CONSTANT 14from aw.Download.Download import * 15from aw.Common.Common import getHostIp, copyFile, copyDirectory 16from aw.ExtractFile.ExtractFile import * 17from aw.poweronoff.serial_power_on_off import usbPowerOnOff 18 19lock_suffix = CONSTANT.File.LOCK_SUFFIX #通过文件锁实现并发下载 20suc_file = CONSTANT.File.SUC_FILE #通过本文件是区分版本是否成功下载 21failed_file = CONSTANT.File.FAILED_FILE #通过本文件是标记文件下载失败 22READ_MAXTIMEOUT = 120 23READ_TIMEOUT = 30 24READ_MINITIMEOUT = 5 25uboot_finish = 'hisilicon #' 26cmd_finish = ' #' 27 28class liteOsUpgrade_L1_shequ_dv(BaseApp): 29 ''' 30 @author: w00278233 31 ''' 32 33 def __init__(self, param_file): 34 super().__init__(param_file) 35 self.param_List = ["deploy_com", 36 "usb_port", 37 "upgrade_upgradeLocation"] 38 39 @dec_stepmsg("hongmeng L1 flash") 40 def excute(self): 41 ''' 42 #=================================================================================== 43 # @Method: excute(self) 44 # @Precondition: none 45 # @Func: 升级执行入口 46 # @PostStatus: none 47 # @eg: excute() 48 # @return: True or Flase 49 #=================================================================================== 50 ''' 51 step_index = self.params_dict.get("step_list").index("liteOsUpgrade_L1_shequ_dv_app") 52 53 # 执行下载 54 try: 55 if not self.download(): 56 CONSTANT.ENVERRMESSAGE = "image download fail" 57 logger.printLog(CONSTANT.ENVERRMESSAGE) 58 return False 59 except Exception as e: 60 raise e 61 62 # 执行升级 63 try: 64 if not self.upgrade(): 65 CONSTANT.ENVERRMESSAGE = "board upgrade fail" 66 logger.printLog(CONSTANT.ENVERRMESSAGE) 67 return False 68 return True 69 except Exception as e: 70 raise e 71 72 @dec_stepmsg("download") 73 @timeout(1800) 74 def download(self): 75 ''' 76 #=================================================================================== 77 # @Method: download(self) 78 # @Precondition: none 79 # @Func: 构建下载到本地的路径,执行相应包的下载 80 # @PostStatus: none 81 # @eg: download() 82 # @return: True or Flase 83 #=================================================================================== 84 ''' 85 global version_savepath, version_name 86 dir_path = CONSTANT.Path.getDirPath() 87 if self.params_dict.get("pbiid"): 88 version_path = self.params_dict.get("pbiid") 89 version_name = str(uuid.uuid5(uuid.NAMESPACE_URL, str(self.params_dict.get("pbiid")) + "FASTBOOT")) 90 version_savepath = os.path.join(dir_path, self.params_dict.get("flash_type"), version_name) 91 else: 92 version_path = self.params_dict.get("upgrade_upgradeLocation") 93 version_name = str(uuid.uuid5(uuid.NAMESPACE_URL, (self.params_dict.get("upgrade_upgradeLocation")))) 94 version_savepath = os.path.join(dir_path, version_name) 95 96 if self.params_dict.get("isDownload") == "True": 97 logger.printLog("不需要做下载,直接返回") 98 return True 99 100 #执行img下载 101 import hashlib 102 save_file_str = version_path.replace("/", "").replace("\\", "") 103 save_file_name = hashlib.sha1(save_file_str.encode("utf-8")).hexdigest() 104 logger.info("download hash string:%s, hash value:%s" % (save_file_str, save_file_name)) 105 save_path_file = os.path.join(dir_path, "record", "%s%s" % (save_file_name, ".txt")) 106 if not self.excutedown(version_path, os.path.join(version_savepath, "img"), save_path_file, False): 107 logger.error("download img fail") 108 return False 109 110 #保存本地版本路径给devicetest去版本路径下取用例 111 saveVersion(save_path_file, os.path.join(version_savepath, "img")) 112 113 #将本地版本push到远程tftp服务器 114 tftp_ip = self.params_dict.get("Tftpserver_IP") 115 if tftp_ip: 116 box_ip = subprocess.getoutput("ipconfig") 117 logger.info("current box ip is: %s" % box_ip) 118 if not tftp_ip in box_ip: 119 logger.info("start to send file") 120 return self.pushFileToTftpServer(tftp_ip, os.path.join(version_savepath, "img"), version_name) 121 return True 122 123 def pushFileToTftpServer(self, tftp_ip, local_file_path, dis_path, username="root", passwd="devicetest@2012"): 124 push_suc = os.path.join(local_file_path, "push_succ.txt") 125 push_fail = os.path.join(local_file_path, "push_fail.txt") 126 push_lock = os.path.join(local_file_path, "push.lock") 127 if os.path.isfile(push_suc): 128 logger.info("push file to tftpserver by other process.") 129 return True 130 elif os.path.isfile(push_fail): 131 logger.info("%s exists. Other process has push package and failed. It will push by self" % push_fail) 132 os.remove(push_fail) 133 else: 134 if os.path.isfile(push_lock): 135 logger.info("wait for other process send succ") 136 ret = waitotherdown(push_suc) 137 return ret 138 139 file_lock = FileLock() 140 file_lock.lockFile(push_lock) 141 142 try: 143 import paramiko 144 logger.info("ip: %s, source_path: %s" % (tftp_ip, local_file_path)) 145 #client = paramiko.Transport((tftp_ip,22), default_window_size=3072) 146 client = paramiko.Transport((tftp_ip,22)) 147 client.connect(username=username,password=passwd) 148 sftp = paramiko.SFTPClient.from_transport(client) 149 #检查tftp服务器根目录,/data或/data/data 150 ret = sftp.listdir(r"/data") 151 server_base_dir = "/data/MobileUpgrade/local_img" 152 if "data" in ret: 153 server_base_dir = "/data/data/MobileUpgrade/local_img" 154 logger.info("server base dir is : %s " % server_base_dir) 155 #检查tftp服务器上有没有本次的版本目录,如果没有则创建文件夹 156 ret = sftp.listdir(server_base_dir) 157 server_des_path = "%s/%s" % (server_base_dir, dis_path) 158 if not dis_path in ret: 159 logger.info("mkdir in tftpserver: %s " % server_des_path) 160 sftp.mkdir(server_des_path) 161 server_img_path = "%s/%s/img" % (server_base_dir, dis_path) 162 logger.info("mkdir in tftpserver: %s " % server_img_path) 163 sftp.mkdir(server_img_path) 164 remote_path = "%s/%s/img" % (server_base_dir, dis_path) 165 logger.info("%s exists." % remote_path) 166 ret = sftp.listdir(remote_path) 167 #如果tftp服务器上有push_succ文件夹,则说明已经由其它进程或box把版本上传成功了。 168 if "push_succ" in ret: 169 logger.info("send file succ by other process") 170 with open(push_suc, "a+") as fp: 171 fp.write("") 172 return True 173 #如果tftp服务器上有push.lock文件夹,则说明有其它进程在向tftp服务器发送版本,等待其它进程发送完毕。 174 elif "push.lock" in ret: 175 logger.info("wait for other process") 176 i = 0 177 while True: 178 time.sleep(10) 179 ret = sftp.listdir(remote_path) 180 if "push_succ" in ret: 181 logger.info("other process succ") 182 return True 183 if i > 6: 184 logger.info("wait 60s, other process failed") 185 break 186 i = i + 1 187 #由本进程向tftp服务器发送版本,先创建push.lock占用上传资源 188 logger.info("mkdir in tftpserver: %s/push.lock " % remote_path) 189 sftp.mkdir("%s/push.lock" % remote_path) 190 pushfilelist = ["OHOS_Image.bin", "rootfs.img", "userfs.img", "rootfs_vfat.img", "userfs_vfat.img", "rootfs_jffs2.img", "userfs_jffs2.img"] 191 for filename in pushfilelist: 192 if not os.path.exists(os.path.join(local_file_path, filename)): 193 continue 194 logger.info("copy %s to %s" % (os.path.join(local_file_path, filename), "%s/%s" % (remote_path, filename))) 195 try: 196 sftp.put(os.path.join(local_file_path, filename), "%s/%s" % (remote_path, filename)) 197 except Exception as e: 198 logger.info("retry, copy %s to %s" % (os.path.join(local_file_path, filename), "%s/%s" % (remote_path, filename))) 199 sftp.put(os.path.join(local_file_path, filename), "%s/%s" % (remote_path, filename)) 200 #创建上传成功标识 201 logger.info("mkdir in tftpserver: %s/push_succ " % remote_path) 202 sftp.mkdir("%s/push_succ" % remote_path) 203 #删除占用标识 204 logger.info("del %s/push.lock " % remote_path) 205 sftp.rmdir("%s/push.lock" % remote_path) 206 with open(push_suc, "a+") as fp: 207 fp.write("") 208 time.sleep(10) 209 return True 210 except (OSError, Exception) as exception: 211 logger.error("copy to file to tftp server failed with error {}".format(exception)) 212 logger.info("del %s/%s " % (server_base_dir, dis_path)) 213 sftp.rmdir("%s/%s" % (server_base_dir, dis_path)) 214 client.close() 215 with open(push_fail, "a+") as fp: 216 fp.write("") 217 return False 218 finally: 219 logger.info("close client") 220 client.close() 221 222 def excutedown(self, source_path, download_dir, suc_mark, is_file): 223 ''' 224 #=================================================================================== 225 # @Method: excutedown(source_path, download_dir, is_file) 226 # @Precondition: none 227 # @Func: 执行下载动作 228 # @PostStatus: none 229 # @Param: source_path:资源文件路径 230 # download_dir:文件下载到本地的文件夹路径 231 # is_file:是否是文件 232 # 233 # @eg: excutedown("xxxx", "D:\\local\\image", Flase, os_method) 234 # @return: True or Flase 235 #=================================================================================== 236 ''' 237 failed_mark = os.path.join(download_dir, failed_file) 238 lock_path = os.path.join(download_dir, lock_suffix) 239 file_lock = FileLock() 240 241 if isDownLoadSuccess(download_dir, suc_mark, failed_mark): 242 return True 243 try: 244 nowtime = get_now_time_str_info() 245 logger.printLog("%s Downloading, please wait" % nowtime) 246 file_lock.lockFile(lock_path) 247 ret = "" 248 logger.info("Get lock. Start to ") 249 if self.params_dict.get("bt_enable") and self.params_dict.get("bt_enable") == "True": 250 ret = downloadByBitComet(source_path, download_dir, os_method) 251 elif source_path.startswith('\\\\'): 252 ret = downloadByCopy(source_path, download_dir, is_file) 253 elif self.params_dict.get("pbiid"): 254 ret = downlaodByDownloadTool(version_savepath, self.params_dict.get("version_type"), "FASTBOOT", self.params_dict.get("pbiid")) 255 elif source_path.startswith("http"): 256 ret = downloadFileFromDevCloud(source_path, "", "", download_dir) 257 258 if source_path.endswith(".zip"): 259 zip_name = os.path.basename(source_path) 260 ret = extractZipFile(os.path.join(download_dir, zip_name), download_dir) 261 if source_path.endswith(".tar.gz") or (source_path.startswith("http") and ("file_id=" in source_path)): 262 if source_path.startswith("http") and ("file_id=" in source_path): 263 if source_path.endswith(".tar.gz"): 264 zip_name = source_path.split('=')[-1] 265 else: 266 zip_name = "out.tar.gz" 267 else: 268 zip_name = os.path.basename(source_path) 269 ret = unTarFile(os.path.join(download_dir, zip_name), download_dir) 270 nowtime = get_now_time_str_info() 271 logger.printLog("%s download to %s end" % (nowtime, download_dir)) 272 273 if not ret: 274 with open(failed_mark, "a+") as fp: 275 fp.write("") 276 return ret 277 except Exception as e: 278 logger.printLog(e) 279 raise Exception(e) 280 finally: 281 file_lock.releaseFile() 282 283 284 @dec_stepmsg("upgrade") 285 #@timeout(900) 286 def upgrade(self): 287 ''' 288 #=================================================================================== 289 # @Method: upgrade(self) 290 # @Precondition: none 291 # @Func: 升级相关业务逻辑 292 # @PostStatus: none 293 # @eg: upgrade() 294 # @return: True or Flase 295 #=================================================================================== 296 ''' 297 298 deploy_com = self.params_dict.get("deploy_com") 299 usb_port = self.params_dict.get("usb_port") 300 baudrate = self.params_dict.get("baudrate") 301 tftp_ip = self.params_dict.get("Tftpserver_IP") 302 device_ip = self.params_dict.get("Device_IP") 303 device_Mac = self.params_dict.get("Device_MAC") 304 device_netmask = self.params_dict.get("Device_Netmask") 305 device_gatewayip = self.params_dict.get("Device_GatewayIP") 306 #芯片类型,根据芯片类型获取对应的刷机命令 307 flash_type = self.params_dict.get("flash_type") 308 309 if not deploy_com: 310 logger.error("deploy_com is NULL !!") 311 return False 312 if not baudrate: 313 baudrate = 115200 314 if not device_netmask: 315 device_netmask = "255.255.252.0" 316 if not device_Mac: 317 device_Mac = "3a:82:d0:08:f4:99" 318 local_image_path = "%s/%s" % (version_name, "img") 319 scriptpath = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(os.path.dirname(__file__))))) 320 scriptfile = os.path.join(scriptpath, "resource", "L1", "dv300_shequ", "update.txt") 321 logger.info("upgrade scriptfile is: %s" % scriptfile) 322 if not os.path.exists(scriptfile): 323 logger.error("%s is not exit" % scriptfile) 324 return False 325 326 logger.info("open com") 327 ser = serial.Serial(deploy_com, int(baudrate), timeout=1) 328 try: 329 logger.info("打开serial") 330 if ser.is_open == False: 331 ser.open() 332 333 logger.info("获取单板状态") 334 board_type = getBoardType(ser) 335 if board_type != "uboot": 336 sendResetCmd(ser, READ_TIMEOUT) 337 board_type = getBoardType(ser) 338 if board_type == "bootrom": 339 if not recoveryBoard(ser, usb_port): 340 logger.error("recovery board fail, please check board") 341 return False 342 343 with open(scriptfile, "r") as fp: 344 lines = fp.readlines() 345 for line in lines: 346 #line = line.strip() 347 if not line: 348 logger.info("cmd is: %s " % line) 349 continue 350 if "%Tftpserver_IP%" in line: 351 line = line.replace("%Tftpserver_IP%", tftp_ip) 352 if "%Device_IP%" in line: 353 line = line.replace("%Device_IP%", device_ip) 354 if "%Device_MAC%" in line: 355 line = line.replace("%Device_MAC%", device_Mac) 356 if "%Device_Netmask%" in line: 357 line = line.replace("%Device_Netmask%", device_netmask) 358 if "%Device_GatewayIP%" in line: 359 line = line.replace("%Device_GatewayIP%", device_gatewayip) 360 if "userfs.img" in line: 361 if not os.path.exists(os.path.join(version_savepath, "img", "userfs.img")): 362 line = line.replace("userfs.img", "userfs_vfat.img") 363 if "rootfs.img" in line: 364 if not os.path.exists(os.path.join(version_savepath, "img", "rootfs.img")): 365 line = line.replace("rootfs.img", "rootfs_vfat.img") 366 if "tftp" in line: 367 packagefile_path = "/%s" % flash_type 368 new_packagefile_path = "/%s" % local_image_path 369 line = line.replace(packagefile_path, new_packagefile_path) 370 ret = sendCmd(ser, line, "hisilicon #", READ_MAXTIMEOUT) 371 if "retry count exceeded; starting again" in ret.lower(): 372 logger.info("tftp cmd retry again!!") 373 ret = sendCmd(ser, line, "hisilicon #", READ_MAXTIMEOUT) 374 if "error:" in ret.lower(): 375 logger.error("tftp fail") 376 return False 377 continue 378 if "reset" in line: 379 ret = sendCmd(ser, line, "OHOS #", READ_TIMEOUT) 380 continue 381 ret = sendCmd(ser, line, " #", READ_MINITIMEOUT) 382 board_type = getBoardType(ser) 383 if board_type == "OHOS": 384 logger.info("upgrade success") 385 init_cmd = "ifconfig eth0 %s netmask %s gateway %s \r" % (device_ip, device_netmask, device_gatewayip) 386 sendCmd(ser, init_cmd, "OHOS #", READ_MINITIMEOUT) 387 sendCmd(ser, 'ifconfig\r', "OHOS #", READ_MINITIMEOUT) 388 return True 389 else: 390 logger.info("upgrade fail") 391 return False 392 except Exception as e: 393 logger.printLog(e) 394 return False 395 finally: 396 ser.close() 397 logger.info("close serial") 398 399 400def boardPowerOn(usb_port): 401 logger.info("board power on start") 402 403 #对端口下电 404 if not usbPowerOnOff('127.0.0.1', '7788', usb_port, "off"): 405 logger.error("board power off failed") 406 return False 407 408 #对端口上电 409 if not usbPowerOnOff('127.0.0.1', '7788', usb_port, "on"): 410 logger.error("board power on failed") 411 return False 412 logger.info("board power on end") 413 414 415def getBoardType(ser): 416 ret = sendCmd(ser, '\r', " #", READ_MINITIMEOUT) 417 if 'HMOS' in ret or 'OHOS' in ret: 418 ostype = 'OHOS' 419 elif 'hisilicon' in ret: 420 ostype = 'uboot' 421 elif ' #' in ret: 422 ostype = 'linux' 423 else: 424 ostype = 'bootrom' 425 logger.info("board type is: %s" % ostype) 426 return ostype 427 428def sendCmd(ser, cmd, endtag, timeout): 429 ser.reset_input_buffer() 430 logger.info("cmd is: %s " % cmd) 431 ser.write((cmd + '\n').encode()) 432 time.sleep(0.5) 433 i = 0 434 ret = '' 435 while True: 436 out = ser.read(ser.inWaiting()) 437 ret = ret + out.decode(encoding="utf-8", errors="ignore") 438 if endtag in ret: 439 logger.info("cmd end") 440 break 441 time.sleep(1) 442 i = i + 1 443 if i > timeout: 444 logger.info("cmd timeout") 445 break 446 logger.info("result is: %s " % ret) 447 return ret 448 449def sendResetCmd(ser, timeout): 450 logger.info("send reset") 451 ser.reset_input_buffer() 452 ser.write(b"reset \r\n") 453 ret = ser.read(ser.inWaiting()) 454 time.sleep(3) 455 #logger.info("result is: %s " % ret) 456 ser.write(b"\r\n") 457 ret = ser.read(ser.inWaiting()) 458 logger.info("result is: %s " % ret) 459 ser.write(b"\r\n") 460 ret = ser.read(ser.inWaiting()) 461 logger.info("result is: %s " % ret) 462 ser.write(b"\r\n") 463 ret = ser.read(ser.inWaiting()) 464 logger.info("result is: %s " % ret) 465 return ret 466 467 468def recoveryBoard(ser, usb_port): 469 logger.info("start recovery board") 470 boardPowerOn(usb_port) 471 #再发送回车 472 ser.write(b"\r\n") 473 time.sleep(0.5) 474 ret = ser.read(ser.inWaiting()) 475 logger.info("result is: %s " % ret) 476 ser.write(b"\r\n") 477 time.sleep(0.5) 478 ret = ser.read(ser.inWaiting()) 479 logger.info("result is: %s " % ret) 480 board_type = getBoardType(ser) 481 if board_type == "bootrom": 482 logger.error("recovery board failed") 483 return False 484 logger.info("recovery board succ") 485 return True 486 487 488if __name__ == "__main__": 489 param_file = sys.argv[1] 490 if not param_file: 491 logger.printLog("Missing params file") 492 sys.exit(-1) 493 try: 494 uphandle = liteOsUpgrade_L1(param_file) 495 uphandle._excuteApp() 496 except Exception as e: 497 logger.printLog(e) 498 sys.exit(-1)