#!/usr/bin/python

"""
    This module contains the deployment script to flash an Intel system in WinPE and Linux using flashupdt
"""

import string, os, os.path, shutil, sys, popen2, systemMgr
from logMgr import addLogRecord,CRITICAL,ERROR,WARNING,INFO,DEBUG
from config import DeploymentStore, DeployPath
from deploymentData import ATSTATE,FAILURE,UPDATE,REFRESH,REBOOT,UNSUPPORTED, UPDATEBIOS, UPDATEMGMT, UPDATEZIPS, UPDATECONFIG, UPDATEMASTER
from flash import getChassisSpec,extractUpdate
try:
    __file__
except:
    __file__ = __name__

def checkState(restore=0):
    """
        checkState() returns ATSTATE if at desired state
        checkState() returns FAILURE if state can't be achieved
        checkState() returns REFRESH if system configuration refresh is needed once flashed
        checkState() returns REBOOT if system reboot is needed once flashed
    """
    if not sys.platform == 'linux2':
        print 'flashupdt is intended for Linux systems only'
        addLogRecord(0,__file__, INFO,'flashupdt is intended for Linux systems only')
        return FAILURE
    ret, BIOSver = systemMgr.queryProperty(0,'SMBIOS','Version','',{'type':'0'})
    if not BIOSver or ret:
        print 'BIOS version unavailable: ret = %d'%ret
        addLogRecord(0,__file__, ERROR,'BIOS version unavailable: ret = %d'%ret)
        return FAILURE
    system = BIOSver.split('.')[0]
    if system == 'S3000':
        ret, BMCver = systemMgr.queryProperty(0,'AMT','Flash version','',{})
        if not BMCver or ret:
            print 'AMT version unavailable: ret = %d'%ret
            addLogRecord(0,__file__, ERROR,'AMT version unavailable: ret = %d'%ret)
            return FAILURE
    else:
        ret, BMCver = systemMgr.queryProperty(0,'SDR','BMC version','',{})
        if not BMCver or ret:
            print 'BMC version unavailable: ret = %d'%ret
            addLogRecord(0,__file__, ERROR,'BMC version unavailable: ret = %d'%ret)
            return FAILURE
    chassis, chassisSpec = getChassisSpec(restore)
    if not chassisSpec:
        return FAILURE
    updateBIOS = chassisSpec[UPDATEBIOS]
    updateBMC = chassisSpec[UPDATEMGMT]
    if not BIOSver.split('.')[UPDATEMASTER] == updateBIOS:
        return REBOOT
    if not BMCver == updateBMC:
        return REFRESH
    print 'BIOS and AMT/BMC at correct versions(%s - %s)'%(BIOSver,BMCver)
    addLogRecord(0,__file__, INFO,'BIOS and AMT/BMC at correct versions(%s - %s)'%(BIOSver,BMCver))
    return ATSTATE


def flashSystem(restore=0):
    state = checkState(restore)
    if state < UPDATE:
        return state
    filePath = extractUpdate(restore)
    if not filePath:
        return FAILURE
    
    print "running an example of flashing BIOS & BMC using ofu ..."
    
    from loadDrivers import getdrvPath
    drvPath = getdrvPath()
    if not drvPath:
        return FAILURE
    drvpath = os.path.join(drvPath,'amifldrv_mod.o')
    flashdir = os.path.join(DeployPath,'Linux','ofu')
    shutil.copyfile(drvpath,os.path.join(flashdir,'amifldrv_mod.o'))
    cwd = os.getcwd()
    os.chdir(flashdir)
    # run out of RAMFS space, so use '> /dev/null'
    cmdObj = popen2.Popen4('./flashupdt -u %s > /dev/null'%filePath)
    status = cmdObj.wait()
    lines = cmdObj.fromchild.read()
    if status:
        print 'flashupdt failed: status = 0x%x, %s'%(status,lines)
        addLogRecord(0,__file__, ERROR,'flashupdt failed: status = 0x%x, %s'%(status,lines))
        return FAILURE
    return state

if __name__ == '__main__':
    """
    this script assumed these enviroment variables have been set:
    (see deploy.sh or deploy.cmd)
        DeployPath
        DeploymentStore
        PATH
        LD_LIBRARY_PATH (Linux)
        PYTHONPATH
    and this script has been run:
        prepareDeployment
    and flash data is located in:
        BootDevice/updates/S5000'
    """
    import time
    if len(sys.argv) == 1:
        restore = 0
    elif len(sys.argv) == 2 and sys.argv[1] == '0':
        restore = 0
    else:
        restore = 1
    state = checkState(restore)
    if state < UPDATE:
        sys.exit(state)
    for i in [1,2,3]:   # try 3 time to get to state
        state = flashSystem(restore)
        if state == ATSTATE:
            print 'BIOS and BMC update succeeded'
            addLogRecord(0,__file__, INFO,'BIOS and BMC update succeeded')
            break
        if state == REBOOT:
            print "System must be reset to complete flash"
            break
        if state == FAILURE:
            break
        time.sleep(5)
        os.system('prepareDeployment refresh')
    else:
        print 'BMC update failed after 3 retries'
        addLogRecord(0,__file__, ERROR,'BMC update  failed after 3 retries')
        state = FAILURE
    sys.exit(state)
