#!/bin/sh
#-----------------------------------------------------
# Filename: curl.sh
# Revision: 6.0.1
# DesignDate：2022/12/13
# Author: H3C/APP
# Description: update firmware based on redfish HDM2
#-----------------------------------------------------
# ChangeLog
# Version 6.0.1
# add update function
#-----------------------------------------------------

FILENAME="curl.sh"
IP=""
PORT=80
USER="admin"
PSWD="Password@_"
FWTYPE=""
FWNAME=""
REBOOT="Manual"
PRESRV="Retain"
BACKUP=false
TOKEN=""
SUBTYPE=""
ACTMODE=""
TRYTIMES=5
GETTIMES=60
SLEEPTIME=30
DELAYTIME=3
CNCTTIME=30
MAXTIME=1800 #30mins
RBTTIME=300
SESSIONID=""

# Usage
function Usage()
{
    echo -e "Usage:"
    echo -e "$1\t\tUpdate HDM or BIOS or CPLD"
    echo -e "Option:"
    echo -e "\t <-I>: HDM IP"
    echo -e "\t <-O>: HDM PORT"
    echo -e "\t <-U>: HDM UserName"
    echo -e "\t <-P>: HDM UserPassword"
    echo -e "\t <-F>: firmware path/name"
    echo -e "\t <-R>: reboot(default 1), 0: Auto, 1: Manual"
    echo -e "\t <-K>: keep configuration(default 0), HDM(0: Retain, 1: Restore factory); BIOS(0: Retain, 1: Restore, 2: ForceRestore-Need power off)"
    echo -e "\t <-B>: backup(default 0), 0: false, 1: true"
}

# IN arg
while getopts "I:O:U:P:F:R:K:B:h" arg
do
    case $arg in
        I)
            IP="$OPTARG"
            ;;
        O)
            PORT="$OPTARG"
            ;;
        U)
            USER="$OPTARG"
            ;;
        P)
            PSWD="$OPTARG"
            ;;
        F)
            FWNAME="rom.ima=@$OPTARG"
            ;;
        R)
            if [[ "0" = "$OPTARG" ]]; then
                REBOOT="Auto"
            elif [[ "1" = "$OPTARG" ]]; then
                REBOOT="Manual"
            else
                REBOOT="Manual"
            fi
            ;;
        K)
            if [[ "0" = "$OPTARG" ]]; then
                PRESRV="Retain"
            elif [[ "1" = "$OPTARG" ]]; then
                PRESRV="Restore"
            elif [[ "2" = "$OPTARG" ]]; then
                PRESRV="ForceRestore"
            else
                PRESRV="Retain"
            fi
            ;;
        B)
            if [[ "0" = "$OPTARG" ]]; then
                BACKUP=false
            elif [[ "1" = "$OPTARG" ]]; then
                BACKUP=true
            else
                BACKUP=false
            fi
            ;;
        h)
            Usage $FILENAME
            exit 0
            ;;
        ?)
            echo "Unknown argment"
            Usage $FILENAME
            exit 1
            ;;
    esac
done

# log path
IP_New=`echo ${IP//:/-}`
mkdir -p ./log/$IP_New
log_path=./log/$IP_New

log_status=$log_path/status.txt
cookies=$log_path/cookies

# Check Input parameter
if [[ "$IP" == "" ]]; then
    echo "No IP is given!!!" >> $log_status
    Usage $FILENAME
    exit 1
fi
if [[ "$FWNAME" == "rom.ima=@" ]]; then
    echo "No firmware file is given!!!" >> $log_status
    Usage $FILENAME
    exit 1
fi

# change some special character
PSWD=`echo $PSWD| sed 's/%/%25/g'`
PSWD=`echo $PSWD| sed 's/+/%2B/g'`
PSWD=`echo $PSWD| sed 's/\//%2F/g'`
PSWD=`echo $PSWD| sed 's/?/%3F/g'`
PSWD=`echo $PSWD| sed 's/#/%23/g'`
PSWD=`echo $PSWD| sed 's/&/%26/g'`
PSWD=`echo $PSWD| sed 's/=/%3D/g'`

# ********
# 功能：记录日志信息
# 参数1：日志信息
# 参数2：日志文件名
# ********
LOG()
{
    local message=$1
    local log_record=$2
    local time_stamp=`date +%F" "%T`
    echo "$time_stamp $message" | tee -a >> $log_record
}

# ********
# 功能：解析ipv6地址
# 参数：无
# *********
func_parse_ipv6()
{
    num=`echo $IP | awk -F ':' '{print NF}'`
    if [ $num -gt 2 ]; then
        IP=`echo "-g [${IP}]"`
    fi
}

# ********
# 功能：创建会话
# 参数：无
# 返回值：0-创建会话成功；1-创建会话失败
# ********
func_establish_session()
{
    local try_time=1
    LOG "Establish session..." $log_status
    while(( $try_time <= $TRYTIMES ))
    do
        ses_inf=`curl -c $cookies -H 'Content-Type:application/json' -X POST -d '{"UserName":"'"$USER"'", "Password":"'"$PSWD"'"}' $IP:$PORT/redfish/v1/SessionService/Sessions --connect-timeout $CNCTTIME -s`
        ses_cc=`echo "$ses_inf" | grep "CompletionCode" | sed -e 's/ //g' -e 's/,//g' | awk -F ':' '{print $2}'`
        if [[ -z "$ses_cc" ]]; then
            LOG "Create session: timeout." $log_status
            let try_time++
            sleep $SLEEPTIME
        elif [[ $ses_cc -eq 0 ]] && [[ `echo "$ses_inf" | grep "X-Auth-Token"` ]]; then
            TOKEN=`echo "$ses_inf" | grep "X-Auth-Token" | sed -e 's/ //g' -e 's/"//g' | awk -F ':' '{print $2}'`
            SESSIONID=`echo "$ses_inf" | grep "@odata.id" | sed -e 's/"//g' -e 's/,//g' | awk -F 'Sessions/' '{print $2}'`
            LOG "Establish session successful! token=$TOKEN, session_id=$SESSIONID." $log_status
            return 0
        else
            ses_desc=`echo "$ses_inf" | grep "Description" | sed -e 's/"//g' -e 's/,//g' | awk -F ':' '{print $2}'`
            LOG "$ses_desc" $log_status
            if [[ `echo $ses_desc | grep "Upgrade is in progress."` ]]; then
                echo "$IP: ${ses_desc}"
                return 1
            fi
            let try_time++
            sleep $SLEEPTIME
        fi
    done
    return 1
}

# *********
# 功能：删除指定会话
# 参数：无
# 返回值：0-删除会话成功；1-删除会话失败
# *********
func_delete_session()
{
    LOG "Delete session..." $log_status
    sess_inf=`curl -c $cookies -b $cookies -H "X-Auth-Token:$TOKEN" -H "Content-Type:application/json" -X DELETE $IP:$PORT/redfish/v1/SessionService/Sessions/$SESSIONID --connect-timeout $CNCTTIME -s`
    sess_cc=`echo "$sess_inf" | grep "CompletionCode" | sed -e 's/ //g' -e 's/,//g' | awk -F ':' '{print $2}'`
    if [[ $sess_cc -ne 0 ]]; then
        sess_desc=`echo "$sess_inf" | grep "Description" | sed -e 's/"//g' -e 's/,//g' | awk -F ':' '{print $2}'`
        LOG "$sess_desc" $log_status
        return 1
    elif [[ -z "$sess_cc" ]]; then
        LOG "Delete session: timeout." $log_status
        return 1
    else
        LOG "Session deleted." $log_status
        return 0
    fi
}

# *********
# 功能：取消升级
# 参数：无
# 返回值：0-取消升级成功；1-取消升级失败
# *********
func_post_update_cancel()
{
    LOG "Ready to cancel update..." $log_status
    can_inf=`curl -c $cookies -b $cookies -H "X-Auth-Token:$TOKEN" -H "Content-Type:application/json" -X POST -d '{}' $IP:$PORT/redfish/v1/UpdateService/Actions/Oem/Public/UpdateService.Cancel --connect-timeout $CNCTTIME -s`
    can_cc=`echo "$can_inf" | grep "CompletionCode" | sed -e 's/ //g' -e 's/,//g' | awk -F ':' '{print $2}'`
    if [[ $can_cc -ne 0 ]]; then
        can_desc=`echo "$can_inf" | grep "Description" | sed 's/"//g' | awk -F ':' '{print $2}'`
        LOG "$can_desc" $log_status
        return 1
    elif [[ -z "$can_cc" ]]; then
        LOG "Cancel: timeout." $log_status
        return 1
    else
        LOG "Update canceled." $log_status
        return 0
    fi
}

# ********
# 功能：升级状态查询
# 参数：无
# 返回值：0-获取到的升级状态为null；1-获取升级状态失败；2-获取到的升级状态为Upgrading
# ********
func_get_upgrade_state()
{
    up_inf=`curl -c $cookies -b $cookies -H "X-Auth-Token:$TOKEN" -H "Content-Type:application/json" -X GET $IP:$PORT/redfish/v1/UpdateService --connect-timeout $CNCTTIME -s`
    up_cc=`echo "$up_inf" | grep "CompletionCode" | sed -e 's/ //g' -e 's/,//g' | awk -F ':' '{print $2}'`
    if [[ -z "$up_cc" ]]; then
        LOG "Get upgrade state: timeout." $log_status
        return 1
    elif [[ $up_cc -eq 0 ]] && [[ `echo "$up_inf" | grep "UpgradeState"` ]]; then
        up_st=`echo "$up_inf" | grep "UpgradeState" | sed -e 's/ //g' -e 's/"//g' | awk -F ':' '{print $2}'`
        if [[ "$up_st" = "Upgrading" ]]; then
            return 2
        else
            return 0
        fi
    else
        up_desc=`echo "$up_inf" | grep "Description" | sed -e 's/"//g' -e 's/,//g' | awk -F ':' '{print $2}'`
        LOG "$up_desc" $log_status
        return 1
    fi
}

# ********
# 功能：为升级准备足够的空间
# 参数：固件文件大小
# 返回值：0-升级准备成功；1-升级准备失败
# ********
func_post_prepare()
{
    LOG "Prepare for update..." $log_status
    local image_size=$1
    pre_inf=`curl -c $cookies -b $cookies -H "X-Auth-Token:$TOKEN" -H "Content-Type:application/json" -X POST -d '{"Type":"multipart/form-data", "FileSizeByte":'$image_size'}' $IP:$PORT/redfish/v1/UpdateService/Actions/Oem/Public/UpdateService.Prepare --connect-timeout $CNCTTIME -s`
    pre_cc=`echo "$pre_inf" | grep "CompletionCode" | sed -e 's/ //g' -e 's/,//g' | awk -F ':' '{print $2}'`
    if [[ $pre_cc -ne 0 ]]; then
        pre_desc=`echo "$pre_inf" | grep "Description" | sed 's/"//g' | awk -F ':' '{print $2}'`
        LOG "$pre_desc" $log_status
        return 1
    elif [[ -z "$pre_cc" ]]; then
        LOG "Prepare: timeout." $log_status
        return 1
    else
        LOG "Update preparation completed." $log_status
        return 0
    fi
}

# ********
# 功能：上传固件
# 参数：固件文件大小
# 返回值：0-上传固件成功；0-上传固件失败
# ********
func_post_upload()
{
    LOG "Uploading the image..." $log_status
    local image_size=$1
    ld_inf=`curl -c $cookies -b $cookies -H "X-Auth-Token:$TOKEN" -H "Content-Type:multipart/form-data" -H "ImageSize:$image_size" -X POST -F $FWNAME --http1.0 $IP:$PORT/redfish/v1/UpdateService/upload --connect-timeout $CNCTTIME --max-time $MAXTIME -s`
    ld_cc=`echo "$ld_inf" | grep "CompletionCode" | sed -e 's/ //g' -e 's/,//g' | awk -F ':' '{print $2}'`
    if [[ $ld_cc -ne 0 ]]; then
        ld_desc=`echo "$ld_inf" | grep "Description" | sed 's/"//g' | awk -F ':' '{print $2}'`
        LOG "$ld_desc" $log_status
        func_post_update_cancel
        return 1
    elif [[ -z "$ld_cc" ]]; then
        LOG "Uploading: timeout." $log_status
        return 1
    else
        LOG "The image is uploaded." $log_status
        return 0
    fi
}

# ********
# 功能：校验固件
# 参数：无
# 返回值：0-校验固件成功；1-校验固件失败
# ********
func_post_verify()
{
    LOG "Verifying the image..." $log_status
    ver_inf=`curl -c $cookies -b $cookies -H "X-Auth-Token:$TOKEN" -H "Content-Type:application/json" -X POST -d '{"FirmwareName":""}' $IP:$PORT/redfish/v1/UpdateService/Actions/Oem/Public/UpdateService.Verify --connect-timeout $CNCTTIME -s`
    ver_cc=`echo "$ver_inf" | grep "CompletionCode" | sed -e 's/ //g' -e 's/,//g' | awk -F ':' '{print $2}'`
    if [[ $ver_cc -ne 0 ]]; then
        ver_desc=`echo "$ver_inf" | grep "Description" | sed 's/"//g' | awk -F ':' '{print $2}'`
        LOG "$ver_desc" $log_status
        return 1
    elif [[ -z "$ver_cc" ]]; then
        LOG "Verify: timeout." $log_status
        return 1
    else
        LOG "The image verify completed." $log_status
        return 0
    fi
}

# ********
# 功能：查询当前处于升级的流程
# 参数：无
# 返回值：0-校验固件完成；1-获取任务状态失败
# ********
func_get_task_status()
{
    while true
    do
        tsk_inf=`curl -c $cookies -b $cookies -H "X-Auth-Token:$TOKEN" -H "Content-Type:application/json" -X GET $IP:$PORT/redfish/v1/UpdateService/Oem/Public/UpdateTaskStatus --connect-timeout $CNCTTIME -s`
        tsk_cc=`echo "$tsk_inf" | grep "CompletionCode" | sed -e 's/ //g' -e 's/,//g' | awk -F ':' '{print $2}'`
        if [[ -z "$tsk_cc" ]]; then
            LOG "Get task status: timeout." $log_status
            return 1
        elif [[ $tsk_cc -eq 0 ]] && [[ `echo "$tsk_inf" | grep "UpgradeState"` ]] && [[ `echo "$tsk_inf" | grep "Ongoing"` ]]; then
            tsk_st=`echo "$tsk_inf" | grep "UpgradeState" | sed -e 's/ //g' -e 's/"//g' | awk -F ':' '{print $2}'`
            on_going=`echo "$tsk_inf" | grep "Ongoing" | sed -e 's/ //g' -e 's/,//g' | awk -F ':' '{print $2}'`
            if [[ "$tsk_st" != "Verify" ]]; then
                LOG "This should be the verify phase, but..." $log_status
                func_post_update_cancel
                return 1
            else
                if [[ "$on_going" = "true" ]]; then
                    sleep $DELAYTIME
                    continue
                else
                    return 0
                fi
            fi
        else
            tsk_desc=`echo "$tsk_inf" | grep "Description" | sed 's/"//g' | awk -F ':' '{print $2}'`
            LOG "Verify:$tsk_desc" $log_status
            return 1
        fi
    done
}

# ************
# 功能：固件上传后，解析固件可升级列表
# 参数：无
# 返回值：0-获取可升级列表成功；1-获取可升级列表失败
# ************
func_get_update_components()
{
    com_inf=`curl -c $cookies -b $cookies -H "X-Auth-Token:$TOKEN" -H "Content-Type:application/json" -X GET $IP:$PORT/redfish/v1/UpdateService/Oem/Public/UpdateComponents --connect-timeout $CNCTTIME -s`
    com_cc=`echo "$com_inf" | grep "CompletionCode" | sed -e 's/ //g' -e 's/,//g' | awk -F ':' '{print $2}'`
    if [[ -z "$com_cc" ]]; then
        LOG "Get component: timeout." $log_status
        return 1
    elif [[ $com_cc -eq 0 ]] && [[ `echo "$com_inf" | grep "FirmwareType"` ]]; then
        FWTYPE=`echo "$com_inf" | grep "FirmwareType" | sed -e 's/ //g' -e 's/"//g' -e 's/,//g' | awk -F ':' '{print $2}'`
        ACTMODE=`echo "$com_inf" | grep "ActiveMode" | sed -e 's/ //g' -e 's/"//g' -e 's/,//g' | awk -F ':' '{print $2}'`
        SUBTYPE=`echo "$com_inf" | grep "SubType" | sed -n 1p | sed 's/"//g' | awk -F ':' '{print $2}'`
        lct_num=`echo "$com_inf" | grep "\"Location\":" | wc -l`
        for ((i=1;i<=${lct_num};i++))
        do
            lct_nam=`echo "$com_inf" | grep "\"Location\":" | sed -n ${i}p | sed -e 's/ //g' -e 's/,//g' -e 's/"//g' | awk -F ':' '{print $2}'`
            cur_ver=`echo "$com_inf" | grep "CurrentVersion" | sed -n ${i}p | sed -e 's/ //g' -e 's/,//g' -e 's/"//g' | awk -F ':' '{print $2}'`
            new_ver=`echo "$com_inf" | grep "NewVersion" | sed -n ${i}p | sed -e 's/ //g' -e 's/,//g' -e 's/"//g' | awk -F ':' '{print $2}'`
            LOG "${lct_nam}: ${cur_ver} -> ${new_ver}" $log_status
        done
        echo "Version: ${cur_ver} -> ${new_ver}"
        com_mem=`echo ${com_inf##*\"Member\":}`
        mem_inf=`echo ${com_mem%%]*}`
        return 0
    else
        com_desc=`echo "$com_inf" | grep "Description" | sed 's/"//g' | awk -F ':' '{print $2}'`
        LOG "$com_desc" $log_status
        return 1
    fi
}

# *********
# 功能：升级回退
# 参数：无
# 返回值：0-升级回退成功；1-升级回退失败
# *********
func_post_update_rollback()
{
    LOG "Ready to rollback..." $log_status
    rol_inf=`curl -c $cookies -b $cookies -H "X-Auth-Token:$TOKEN" -H "Content-Type:application/json" -X POST -d '{}' $IP:$PORT/redfish/v1/UpdateService/Actions/Oem/Public/UpdateService.Rollback --connect-timeout $CNCTTIME -s`
    rol_cc=`echo "$rol_inf" | grep "CompletionCode" | sed -e 's/ //g' -e 's/,//g' | awk -F ':' '{print $2}'`
    if [[ $rol_cc -ne 0 ]]; then
        rol_desc=`echo "$rol_inf" | grep "Description" | sed 's/"//g' | awk -F ':' '{print $2}'`
        LOG "$rol_desc" $log_status
        return 1
    elif [[ -z "$rol_cc" ]]; then
        LOG "rollback: timeout." $log_status
        return 1
    else
        LOG "Update rollback." $log_status
        return 0
    fi
}

# ********
# 功能：升级
# 参数：无
# 返回值：0-执行升级任务成功；1-执行升级任务失败
# ********
func_post_update()
{
    LOG "Updating the image..." $log_status
    upd_inf=`curl -c $cookies -b $cookies -H "X-Auth-Token:$TOKEN" -H "Content-Type:application/json" -X POST -d '{"FirmwareList":[{"FirmwareType":"'"$FWTYPE"'","Preserve":"'"$PRESRV"'","RebootMode":"'"$REBOOT"'","Backup":'$BACKUP'}]}' $IP:$PORT/redfish/v1/UpdateService/Actions/Oem/Public/UpdateService.Update --connect-timeout $CNCTTIME -s`
    upd_cc=`echo "$upd_inf" | grep "CompletionCode" | sed -e 's/ //g' -e 's/,//g' | awk -F ':' '{print $2}'`
    if [[ $upd_cc -ne 0 ]]; then
        upd_desc=`echo "$upd_inf" | grep "Description" | sed 's/"//g' | awk -F ':' '{print $2}'`
        LOG "$upd_desc" $log_status
        return 1
    elif [[ -z "$upd_cc" ]]; then
        LOG "Update: timeout." $log_status
        return 1
    else
        return 0
    fi
}

# ********
# 功能：查询当前处于升级的流程和进度
# 参数：无
# 返回值：0-升级完成；1-查询升级进度失败
# ********
func_get_update_progress()
{
    while true
    do
        tsk_inf=`curl -c $cookies -b $cookies -H "X-Auth-Token:$TOKEN" -H "Content-Type:application/json" -X GET $IP:$PORT/redfish/v1/UpdateService/Oem/Public/UpdateTaskStatus --connect-timeout $CNCTTIME -s`
        tsk_cc=`echo "$tsk_inf" | grep "CompletionCode" | sed -e 's/ //g' -e 's/,//g' | awk -F ':' '{print $2}'`
        if [[ -z "$upd_cc" ]]; then
            LOG "Get task status: timeout." $log_status
            return 1
        elif [[ $tsk_cc -eq 0 ]] && [[ `echo "$tsk_inf" | grep "UpgradeState"` ]] && [[ `echo "$tsk_inf" | grep "Ongoing"` ]]; then
            tsk_st=`echo "$tsk_inf" | grep "UpgradeState" | sed -e 's/ //g' -e 's/"//g' | awk -F ':' '{print $2}'`
            on_going=`echo "$tsk_inf" | grep "Ongoing" | sed -e 's/ //g' -e 's/,//g' | awk -F ':' '{print $2}'`
            if [[ "$tsk_st" != "Uping" ]]; then
                LOG "This should be the update phase, but..." $log_status
                return 1
            else
                prg_inf=`curl -c $cookies -b $cookies -H "X-Auth-Token:$TOKEN" -H "Content-Type:application/json" -X GET $IP:$PORT/redfish/v1/UpdateService/Oem/Public/UpdateTaskProgress --connect-timeout $CNCTTIME -s`
                prg_cc=`echo "$prg_inf" | grep "CompletionCode" | sed -e 's/ //g' -e 's/,//g' | awk -F ':' '{print $2}'`
                if [[ -z "$prg_cc" ]]; then
                    LOG "Get task progress: timeout." $log_status
                    return 1
                elif [[ $prg_cc -eq 0 ]] && [[ `echo "$prg_inf" | grep "\"Location\":"` ]] && [[ `echo "$prg_inf" | grep "\"Progress\":"` ]]; then
                    loc_num=`echo "$prg_inf" | grep "\"Location\":" | wc -l`
                    for ((i=1;i<=${loc_num};i++))
                    do
                        loc_nam=`echo "$prg_inf" | grep "\"Location\":" | sed -n ${i}p | sed -e 's/ //g' -e 's/,//g' -e 's/"//g' | awk -F ':' '{print $2}'`
                        loc_prg=`echo "$prg_inf" | grep "\"Progress\":" | sed -n ${i}p | sed -e 's/ //g' -e 's/,//g' | awk -F ':' '{print $2}'`
                        echo -n "${loc_nam}:${loc_prg}% "
                        LOG "${loc_nam}:${loc_prg}% " $log_status
                    done
                    printf "\r"
                fi
            fi
            if [[ "$on_going" = "true" ]]; then
                sleep $DELAYTIME
                continue
            else
                printf "\n$IP: $FWTYPE firmware upgrade completed."
                printf "\n$IP: $FWTYPE active mode: $ACTMODE\n"
                LOG "$FWTYPE firmware upgrade completed." $log_status
                LOG "$FWTYPE active mode: $ACTMODE" $log_status
                return 0
            fi
        else
            tsk_desc=`echo "$tsk_inf" | grep "Description" | sed 's/"//g' | awk -F ':' '{print $2}'`
            LOG "Updating:$tsk_desc" $log_status
            return 1
        fi
    done
}

# ********
# 功能：获取电源状态
# 参数：无
# 返回值：0-关机状态；1-开机状态；2-获取电源状态失败
# ********
func_get_power_state()
{
    chs_inf=`curl -c $cookies -b $cookies -H "X-Auth-Token:$TOKEN" -H "Content-Type:application/json" -X GET $IP:$PORT/redfish/v1/Chassis --connect-timeout $CNCTTIME -s`
    chs_cc=`echo "$chs_inf" | grep "CompletionCode" | sed -e 's/ //g' -e 's/,//g' | awk -F ':' '{print $2}'`
    chs_id=`echo "$chs_inf" | grep "@odata.id" | sed -n 2p | sed -e 's/"//g' -e 's/,//g' | awk -F 'Chassis/' '{print $2}'`
    if [[ -z "$chs_cc" ]] && [[ -z "$chs_id" ]]; then
        LOG "Get chassis info: timeout." $log_status
    elif [[ $chs_cc -eq 0 ]]; then
        for ((a=1;a<=$TRYTIMES;a++))
        do
            # 用于查询电源状态
            chs_id_inf=`curl -c $cookies -b $cookies -H "X-Auth-Token:$TOKEN" -H "Content-Type:application/json" -X GET $IP:$PORT/redfish/v1/Chassis/${chs_id} --connect-timeout $CNCTTIME -s`
            chs_id_cc=`echo "$chs_id_inf" | grep "CompletionCode" | sed -e 's/ //g' -e 's/,//g' | awk -F ':' '{print $2}'`
            pwr_sta=`echo "$chs_id_inf" | grep "PowerState" | sed -e 's/ //g' -e 's/,//g' -e 's/"//g' | awk -F ':' '{print $2}'`
            if [[ "x$chs_id_cc" = "x" ]] && [[ "x$pwr_sta" = "x" ]]; then
                LOG "Get chassis id info: timeout." $log_status
                continue
            elif [[ $chs_id_cc -eq 0 ]] && [[ "On" = "$pwr_sta" ]]; then # 处于开机状态
                return 1
            elif [[ $chs_id_cc -eq 0 ]] && [[ "Off" = "$pwr_sta" ]]; then # 处于关机状态
                return 0
            else
                chs_id_desc=`echo "$chs_id_inf" | grep "Description" | sed 's/"//g' | awk -F ':' '{print $2}'`
                LOG "$chs_id_desc" $log_status
                continue
            fi
        done
    else
        chs_desc=`echo "$chs_inf" | grep "Description" | sed 's/"//g' | awk -F ':' '{print $2}'`
        LOG "$chs_desc" $log_status
    fi
    LOG "Get power state failed!" $log_status
    return 2
}

# ********
# 功能：升级主流程
# 参数：无
# 返回值：0-升级成功；1-升级不成功；2-创建会话失败
# ********
update_main()
{
    func_parse_ipv6
    func_establish_session
    [[ $? -ne 0 ]] && return 2
    func_get_upgrade_state
    ren=$?
    if [[ $ren -ne 0 ]]; then
        if [[ $ren -eq 2 ]]; then
            LOG "Other users are updating firmware, please wait..." $log_status
        fi
        return 1
    fi
    image_file=`echo $FWNAME | awk -F '@' '{print $2}'`
    image_size=`ls -l $image_file | awk '{print $5}' | sed 's/ //g'`
    LOG "image_size: $image_size" $log_status
    func_post_prepare $image_size
    [[ $? -ne 0 ]] && return 1
    func_post_upload $image_size
    [[ $? -ne 0 ]] && return 1
    func_post_verify
    [[ $? -ne 0 ]] && return 1
    func_get_task_status
    [[ $? -ne 0 ]] && return 1
    func_get_update_components
    [[ $? -ne 0 ]] && return 1
    func_get_power_state
    local pwr_st=$?
    if [[ "HDM" = "$FWTYPE" ]] || [[ "BMC" = "$FWTYPE" ]] && [[ "ForceRestore" = "$PRESRV" ]]; then # HDM应该为恢复出厂配置
        PRESRV="Retain"
    elif [[ "BIOS" = "$FWTYPE" ]] && [[ "ForceRestore" = "$PRESRV" ]]; then # BIOS强制覆盖升级需要主机下电
        if [[ $pwr_st -ne 0 ]]; then
            func_post_update_rollback
            if [[ $pwr_st -eq 1 ]]; then
                func_delete_session
                printf "\n$IP: Forced overwrite upgrade can only be done when the host is powered off.\n"
                LOG "The host need power off." $log_status
                exit 2
            elif [[ $pwr_st -eq 2 ]]; then
                return 1
            fi
        fi
    fi
    func_post_update
    [[ $? -ne 0 ]] && return 1
    func_get_update_progress
    [[ $? -ne 0 ]] && return 1
    if [[ "HDM" = "$FWTYPE" ]] || [[ "BMC" = "$FWTYPE" ]] && [[ "Auto" = "$REBOOT" ]] && [[ "Retain" = "$PRESRV" ]]; then # HDM升级完成后重启
        func_delete_session # 同版本HDM升级时可能不会重启
        echo "$IP: After upgrading $FWTYPE firmware, reset BMC, please wait a moment..."
        sleep $RBTTIME
        for ((i=1;i<=$TRYTIMES;i++))
        do
            func_establish_session
            if [[ $? -ne 0 ]]; then
                continue
            else
                let i=$TRYTIMES+1
                for ((j=1;j<=$TRYTIMES;j++))
                do
                    func_get_upgrade_state # 查询升级状态，确保能进行下一次升级
                    [[ $? -eq 0 ]] && break # 升级状态为null
                    sleep $SLEEPTIME
                done
            fi
        done
    elif [[ "BIOS" = "$FWTYPE" ]] && [[ "Auto" = "$REBOOT" ]] && [[ "ForceRestore" != "$PRESRV" ]] && [[ $pwr_st -eq 1 ]]; then # 开机状态下BIOS升级完成后重启
        echo "$IP: After upgrading $FWTYPE firmware, restart BIOS, please wait a moment..."
        local upg_flag=0
        for ((n=0;n<$GETTIMES;n++)) # 轮询等待状态从null->Upgrading最长30mins
        do
            func_get_upgrade_state
            if [[ $? -eq 2 ]]; then # 升级状态为Upgrading
                upg_flag=1
                break
            fi
            sleep $SLEEPTIME
        done
        if [[ $upg_flag -eq 1 ]]; then
            while true; do # 超时后状态会自动置为null
                func_get_upgrade_state
                [[ $? -eq 0 ]] && break # 升级状态为null
                sleep $SLEEPTIME
            done
        fi
    fi
    return 0
}

update_main
ret=$?
if [[ $ret -eq 1 ]]; then
    func_delete_session
    printf "\n$IP: $FWTYPE firmware upgrade unsuccessful.\n"
    LOG "$FWTYPE firmware upgrade unsuccessful." $log_status
    exit 1
elif [[ $ret -eq 2 ]]; then
    printf "\n$IP: Created session failed.\n"
    LOG "Created session failed." $log_status
    exit 1
else
    func_delete_session
    exit 0
fi
