• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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)