Helper method to parse upgrade data from the NX-OS device.

def _parse_upgrade_data(data):
    '''
    Helper method to parse upgrade data from the NX-OS device.
    '''
    upgrade_result = {}
    upgrade_result['upgrade_data'] = None
    upgrade_result['succeeded'] = False
    upgrade_result['upgrade_required'] = False
    upgrade_result['upgrade_non_disruptive'] = False
    upgrade_result['upgrade_in_progress'] = False
    upgrade_result['installing'] = False
    upgrade_result['module_data'] = {}
    upgrade_result['error_data'] = None
    upgrade_result['backend_processing_error'] = False
    upgrade_result['invalid_command'] = False

    # Error handling
    if isinstance(data, string_types) and re.search('Code: 500', data):
        log.info('Detected backend processing error')
        upgrade_result['error_data'] = data
        upgrade_result['backend_processing_error'] = True
        return upgrade_result

    if isinstance(data, dict):
        if 'code' in data and data['code'] == '400':
            log.info('Detected client error')
            upgrade_result['error_data'] = data['cli_error']

            if re.search('install.*may be in progress', data['cli_error']):
                log.info('Detected install in progress...')
                upgrade_result['installing'] = True

            if re.search('Invalid command', data['cli_error']):
                log.info('Detected invalid command...')
                upgrade_result['invalid_command'] = True
        else:
            # If we get here then it's likely we lost access to the device
            # but the upgrade succeeded.  We lost the actual upgrade data so
            # set the flag such that impact data is used instead.
            log.info('Probable backend processing error')
            upgrade_result['backend_processing_error'] = True
        return upgrade_result

    # Get upgrade data for further parsing
    # Case 1: Command terminal dont-ask returns empty {} that we don't need.
    if isinstance(data, list) and len(data) == 2:
        data = data[1]
    # Case 2: Command terminal dont-ask does not get included.
    if isinstance(data, list) and len(data) == 1:
        data = data[0]

    log.info('Parsing NX-OS upgrade data')
    upgrade_result['upgrade_data'] = data
    for line in data.split('\n'):

        log.info('Processing line: (%s)', line)

        # Check to see if upgrade is disruptive or non-disruptive
        if re.search(r'non-disruptive', line):
            log.info('Found non-disruptive line')
            upgrade_result['upgrade_non_disruptive'] = True

        # Example:
        # Module  Image  Running-Version(pri:alt)  New-Version  Upg-Required
        # 1       nxos   7.0(3)I7(5a)              7.0(3)I7(5a)        no
        # 1       bios   v07.65(09/04/2018)        v07.64(05/16/2018)  no
        mo = re.search(r'(\d+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(yes|no)', line)
        if mo:
            log.info('Matched Module Running/New Version Upg-Req Line')
            bk = 'module_data'  # base key
            g1 = mo.group(1)
            g2 = mo.group(2)
            g3 = mo.group(3)
            g4 = mo.group(4)
            g5 = mo.group(5)
            mk = 'module {0}:image {1}'.format(g1, g2)  # module key
            upgrade_result[bk][mk] = {}
            upgrade_result[bk][mk]['running_version'] = g3
            upgrade_result[bk][mk]['new_version'] = g4
            if g5 == 'yes':
                upgrade_result['upgrade_required'] = True
                upgrade_result[bk][mk]['upgrade_required'] = True
            continue

        # The following lines indicate a successfull upgrade.
        if re.search(r'Install has been successful', line):
            log.info('Install successful line')
            upgrade_result['succeeded'] = True
            continue

        if re.search(r'Finishing the upgrade, switch will reboot in', line):
            log.info('Finishing upgrade line')
            upgrade_result['upgrade_in_progress'] = True
            continue

        if re.search(r'Switch will be reloaded for disruptive upgrade', line):
            log.info('Switch will be reloaded line')
            upgrade_result['upgrade_in_progress'] = True
            continue

        if re.search(r'Switching over onto standby', line):
            log.info('Switching over onto standby line')
            upgrade_result['upgrade_in_progress'] = True
            continue

    return upgrade_result