#!/usr/bin/env python

# Copyright C 2008-2012 by Isilon Systems LLC. All rights not expressly
# granted herein are reserved.
# Created in the United States of America.
# 
# This digital media is protected by U.S. and international copyright and
# intellectual property laws. Unless otherwise specified, all information
# and screens appearing as part of this digital medium, including
# software, services, documents, text, images, icons, and logos design;
# the selection, assembly, arrangement, and design thereof; and the code
# that enables its presentation, are the sole property of Isilon Systems,
# Inc.
# 
# Except as otherwise required by applicable law, no part of any
# copyrighted material may be reproduced, modified, translated,
# distributed, published, or transmitted by any means, electronic or
# mechanical, for any purpose, without the prior written consent of Isilon
# Systems. 
#  
# Isilon and Isilon Systems are registered trademarks of Isilon Systems,
# Inc.  Legion is a trademark of Isilon Systems, Inc.  All other
# trademarks and registered trademarks are the property of their
# respective holders.

# This script determines if a "isi_fcb_vpd_tool pull" call is necessary
# and calls the pull command if needed.

import getopt
import os
import sys
import re

import isi.hw.hal as hal
import isi.hw.dongle as hwdongle
import isi.app.lib.procs as procs

# Substrings for matching EEPROM SKU
EEPROM_851_SUBSTR = "'851-"
EEPROM_812_SUBSTR = "'812-"
EEPROM_400_SUBSTR = "'400-"

# Substrings for matching disk SKU
ETC_851_SUBSTR = "851-"
ETC_812_SUBSTR = "812-"
ETC_400_SUBSTR = "400-"

#------------------------------------------------------------------------------
def bmc_pull():
    if hwdongle.bmc_pull():
        print "BMC Pull Failed"

def eeprom_pull():
    eepromSKU = 0
    diskSKU = 0
    serialFound = False
    sysConfigFound = False
    eepromFoundSysConfig = ""

    # Get system config from EEPROM
    dumpCmd = '/usr/bin/isi_hwtools/isi_fcb_vpd_tool dump'
    (errorDump, outputDump) = procs.get_cmd_output(dumpCmd)
    if errorDump:
        print "Error: isi_fcb_vpd_tool dump failed, " \
            "could not get VPD from EEPROM"

    # Get system config from /etc
    try:
        with open('/etc/isilon_system_config', 'r') as f:
            readSysConfigEtc = f.readline()
        sysConfigEtc = readSysConfigEtc[:4]
    except EnvironmentError:
        sysConfigEtc = ""
        readSysConfigEtc = ""
        print "Could not get VPD from disk"

    # Determine EEPROM system config and serial number
    sysConfigRegex = re.compile("\s*\S*/etc/isilon_system_config\s*:\s*\[\s*"
                "(?P<conf>\S+)\s*.*")
    serialRegex = re.compile("\s*\S*/etc/isilon_serial_number\s*:\s*\[\s*"
                "(?P<serial>\S+)\s*.*")

    for line in outputDump:
        sysConfigMatch = sysConfigRegex.match(line)
        serialMatch = serialRegex.match(line)
        if serialMatch and not serialFound:
            serialFound = True
            eepromFoundSerialNo = serialMatch.group("serial")
        elif not serialMatch and not serialFound:
            serialFound = False
        if sysConfigMatch and not sysConfigFound:
            eepromFoundSysConfig = sysConfigMatch.group("conf")
            if EEPROM_851_SUBSTR in sysConfigMatch.group("conf"):
                eepromSKU = 851
                sysConfigFound = True
                continue
            elif EEPROM_812_SUBSTR in sysConfigMatch.group("conf"):
                eepromSKU = 812
                sysConfigFound = True
                continue
            elif EEPROM_400_SUBSTR in sysConfigMatch.group("conf"):
                eepromSKU = 400
                sysConfigFound = True
                continue
            else:
                eepromSKU = 0
        elif not sysConfigMatch and not sysConfigFound:
            eepromSKU = 0

    # Print system config from EEPROM
    if eepromFoundSysConfig:
        print("System Config Number in EEPROM is: %s" % 
              eepromFoundSysConfig.strip(" '],"))

    # Print system config from disk
    if readSysConfigEtc:
        print("/etc/isilon_system_config contains: %s" % 
              readSysConfigEtc.rstrip('\n'))

    # Print serial number from EEPROM
    if serialFound:
        print("Serial Number in EEPROM is: %s" % 
              eepromFoundSerialNo.strip(" '],"))
    else:
        print "Could not get Serial Number from EEPROM"
 
    # Print serial number from /etc 
    try:
        with open('/etc/isilon_serial_number', 'r') as f:
            diskSerialNumber = f.readline()
        print("/etc/isilon_serial_number contains: %s" % 
              diskSerialNumber.rstrip('\n'))
    except EnvironmentError:
        print "Could not get Serial Number from disk"

    # Determine disk SKU
    if ETC_851_SUBSTR in sysConfigEtc:
        diskSKU = 851
    elif ETC_812_SUBSTR in sysConfigEtc:
        diskSKU = 812
    elif ETC_400_SUBSTR in sysConfigEtc:
        diskSKU = 400
    else:
        diskSKU = 0

    # Logic for executing VPD pull if necessary
    pullCmd = '/usr/bin/isi_hwtools/isi_fcb_vpd_tool pull'
    if ((eepromSKU == 400 or eepromSKU == 851) and diskSKU == 0):
        (errorPull, outputPull) = procs.get_cmd_output(pullCmd)
        if errorPull:
            print "Error: isi_fcb_vpd_tool pull failed, could not pull VPD " \
                "from EEPROM to disk"
        else:
            print "Pulling VPD from EEPROM to create disk copy"
    elif ((diskSKU == 851 and eepromSKU == 851) or \
            (diskSKU == 400 and eepromSKU == 400)):
        (errorPull, outputPull) = procs.get_cmd_output(pullCmd)
        if errorPull:
            print "Error: isi_fcb_vpd_tool pull failed, could not pull VPD " \
                "from EEPROM to disk"
        elif diskSKU == 851:
            print "Node SKUs appear correct, pulling VPD from EEPROM to disk"
        elif diskSKU == 400:
            print "Node System Config Number appears correct (CTO node), " \
                "pulling VPD from EEPROM to disk"
    elif (diskSKU == 851 and eepromSKU == 812):
        print "Pending disk tango, not pulling VPD from EEPROM to disk"
    elif (diskSKU == 812 and eepromSKU == 812):
        print "Warning: 812 SKU on disk and in EEPROM, not pulling VPD from " \
            "EEPROM to disk"
    else:
        print "Error: Not pulling VPD from EEPROM to disk due to invalid " \
            "System Config Number"
        if diskSKU == 0:
            print "Error: Invalid System Config Number on disk"
        if eepromSKU == 0:
            print "Error: Invalid System Config Number in EEPROM"

def eeprom_sysconfig_read():
    sysconfig = None
    regex = re.compile("\s*\S*/etc/isilon_system_config" 
                       "\s*=\s*\[\s*'(?P<conf>\S+)'\s*.*")
    cmd = ("/usr/bin/isi_hwtools/isi_fcb_vpd_tool read"
           " '$LEGACY_/etc/isilon_system_config'")
    error, output = procs.get_cmd_output(cmd) 
    if not error and len(output):
        for line in output:
            match = regex.match(line)
            if match:
                sysconfig = match.group('conf')
    return sysconfig

def bmc_sysconfig_read():
    sysconfig = None
    cmd = ('/usr/local/sbin/dmidecode -s "chassis-version"')
    error, output = procs.get_cmd_output(cmd)
    if not error and len(output):
        sysconfig = output[0]
    return sysconfig 

def reimage_pull():
    if hal.supportsChassisVpdEeprom():
        print 'Pulling System Config Number from EEPROM'
        sysconfig = eeprom_sysconfig_read()
    elif hal.supportsBMC():
        print 'Pulling System Config Number from BMC'
        sysconfig = bmc_sysconfig_read()
    else:
        sysconfig = None
    if sysconfig:
        print 'System Config Number: %s' % sysconfig
        with open('/etc/isilon_system_config', 'w') as f:
            f.write('%s\n' % sysconfig)
            f.flush()
    else:
        print 'Unable to get System Config Number'

def main(argv):
    reimage = False
    try:
        opts, args = getopt.getopt(argv, "r", ['reImage'])
    except getopt.GetoptError, err:
        print str(err)
        sys.exit(1)
        
    for opt, arg in opts:
        if opt in ['-r', '--reImage']:
            reimage = True

    # As part of 7.1.0, USB reimages now run isi_inventory_tool.
    # For Bug 109508, a way to determine whether a S/X200
    # is CTO or SKU was needed. To accomplish this, the reImage
    # flag was added to isi_vpd_pull to only pull the system config
    # number and write it to disk.
    if reimage:
        reimage_pull()
        return

    if hal.supportsChassisVpdEeprom():
        eeprom_pull()
    elif hal.supportsBMC():
        bmc_pull()
    else:
        return

#------------------------------------------------------------------------------
if __name__ == "__main__":
    main(sys.argv[1:])
