#!/usr/bin/env python

r"""
Provide useful ipmi functions.
"""

import re
import gen_print as gp
import gen_misc as gm
import gen_robot_keyword as grk
import gen_robot_utils as gru
import bmc_ssh_utils as bsu
import var_funcs as vf
import tempfile
gru.my_import_resource("ipmi_client.robot")
from robot.libraries.BuiltIn import BuiltIn


def get_sol_info():
    r"""
    Get all SOL info and return it as a dictionary.

    Example use:

    Robot code:
    ${sol_info}=  get_sol_info
    Rpvars  sol_info

    Output:
    sol_info:
      sol_info[Info]:                                SOL parameter 'Payload Channel (7)' not supported - defaulting to 0x0e
      sol_info[Character Send Threshold]:            1
      sol_info[Force Authentication]:                true
      sol_info[Privilege Level]:                     USER
      sol_info[Set in progress]:                     set-complete
      sol_info[Retry Interval (ms)]:                 100
      sol_info[Non-Volatile Bit Rate (kbps)]:        IPMI-Over-Serial-Setting
      sol_info[Character Accumulate Level (ms)]:     100
      sol_info[Enabled]:                             true
      sol_info[Volatile Bit Rate (kbps)]:            IPMI-Over-Serial-Setting
      sol_info[Payload Channel]:                     14 (0x0e)
      sol_info[Payload Port]:                        623
      sol_info[Force Encryption]:                    true
      sol_info[Retry Count]:                         7
    """

    status, ret_values = grk.run_key_u("Run IPMI Standard Command  sol info")

    # Create temp file path.
    temp = tempfile.NamedTemporaryFile()
    temp_file_path = temp.name

    # Write sol info to temp file path.
    text_file = open(temp_file_path, "w")
    text_file.write(ret_values)
    text_file.close()

    # Use my_parm_file to interpret data.
    sol_info = gm.my_parm_file(temp_file_path)

    return sol_info


def set_sol_setting(setting_name, setting_value):
    r"""
    Set SOL setting with given value.

    # Description of argument(s):
    # setting_name    SOL setting which needs to be set (e.g. "retry-count").
    # setting_value   Value which needs to be set (e.g. "7").
    """

    status, ret_values = grk.run_key_u("Run IPMI Standard Command  sol set " +
                                       setting_name + " " + setting_value)

    return status


def get_lan_print_dict():
    r"""
    Get IPMI 'lan print' output and return it as a dictionary.

    Here is an example of the IPMI lan print output:

    Set in Progress         : Set Complete
    Auth Type Support       : MD5
    Auth Type Enable        : Callback : MD5
                            : User     : MD5
                            : Operator : MD5
                            : Admin    : MD5
                            : OEM      : MD5
    IP Address Source       : Static Address
    IP Address              : x.x.x.x
    Subnet Mask             : x.x.x.x
    MAC Address             : xx:xx:xx:xx:xx:xx
    Default Gateway IP      : x.x.x.x
    802.1q VLAN ID          : Disabled
    Cipher Suite Priv Max   : Not Available
    Bad Password Threshold  : Not Available

    Given that data, this function will return the following dictionary.

    lan_print_dict:
      [Set in Progress]:                              Set Complete
      [Auth Type Support]:                            MD5
      [Auth Type Enable]:
        [Callback]:                                   MD5
        [User]:                                       MD5
        [Operator]:                                   MD5
        [Admin]:                                      MD5
        [OEM]:                                        MD5
      [IP Address Source]:                            Static Address
      [IP Address]:                                   x.x.x.x
      [Subnet Mask]:                                  x.x.x.x
      [MAC Address]:                                  xx:xx:xx:xx:xx:xx
      [Default Gateway IP]:                           x.x.x.x
      [802.1q VLAN ID]:                               Disabled
      [Cipher Suite Priv Max]:                        Not Available
      [Bad Password Threshold]:                       Not Available

    """

    IPMI_INBAND_CMD = BuiltIn().get_variable_value("${IPMI_INBAND_CMD}")

    # Notice in the example of data above that 'Auth Type Enable' needs some
    # special processing.  We essentially want to isolate its data and remove
    # the 'Auth Type Enable' string so that key_value_outbuf_to_dict can
    # process it as a sub-dictionary.
    cmd_buf = IPMI_INBAND_CMD + " lan print | grep -E '^(Auth Type Enable)" +\
        "?[ ]+: ' | sed -re 's/^(Auth Type Enable)?[ ]+: //g'"
    stdout1, stderr, rc = bsu.os_execute_command(cmd_buf)

    # Now get the remainder of the data and exclude the lines with no field
    # names (i.e. the 'Auth Type Enable' sub-fields).
    cmd_buf = IPMI_INBAND_CMD + " lan print | grep -E -v '^[ ]+: '"
    stdout2, stderr, rc = bsu.os_execute_command(cmd_buf)

    # Make auth_type_enable_dict sub-dictionary...
    auth_type_enable_dict = vf.key_value_outbuf_to_dict(stdout1, to_lower=0,
                                                        underscores=0)

    # Create the lan_print_dict...
    lan_print_dict = vf.key_value_outbuf_to_dict(stdout2, to_lower=0,
                                                 underscores=0)
    # Re-assign 'Auth Type Enable' to contain the auth_type_enable_dict.
    lan_print_dict['Auth Type Enable'] = auth_type_enable_dict

    return lan_print_dict


def get_ipmi_power_reading(strip_watts=1):
    r"""
    Get IPMI power reading data and return it as a dictionary.

    The data is obtained by issuing the IPMI "power reading" command.  An
    example is shown below:

    Instantaneous power reading:                   234 Watts
    Minimum during sampling period:                234 Watts
    Maximum during sampling period:                234 Watts
    Average power reading over sample period:      234 Watts
    IPMI timestamp:                           Thu Jan  1 00:00:00 1970
    Sampling period:                          00000000 Seconds.
    Power reading state is:                   deactivated

    For the data shown above, the following dictionary will be returned.

    result:
      [instantaneous_power_reading]:              238 Watts
      [minimum_during_sampling_period]:           238 Watts
      [maximum_during_sampling_period]:           238 Watts
      [average_power_reading_over_sample_period]: 238 Watts
      [ipmi_timestamp]:                           Thu Jan  1 00:00:00 1970
      [sampling_period]:                          00000000 Seconds.
      [power_reading_state_is]:                   deactivated

    Description of argument(s):
    strip_watts  Strip all dictionary values of the trailing " Watts"
                 substring.
    """

    status, ret_values = \
        grk.run_key_u("Run IPMI Standard Command  dcmi power reading")
    result = vf.key_value_outbuf_to_dict(ret_values)

    if strip_watts:
        result.update((k, re.sub(' Watts$', '', v)) for k, v in result.items())

    return result


def get_mc_info():
    r"""
    Get IPMI mc info data and return it as a dictionary.

    The data is obtained by issuing the IPMI "mc info" command.  An
    example is shown below:

    Device ID                 : 0
    Device Revision           : 0
    Firmware Revision         : 2.01
    IPMI Version              : 2.0
    Manufacturer ID           : 42817
    Manufacturer Name         : Unknown (0xA741)
    Product ID                : 16975 (0x424f)
    Product Name              : Unknown (0x424F)
    Device Available          : yes
    Provides Device SDRs      : yes
    Additional Device Support :
        Sensor Device
        SEL Device
        FRU Inventory Device
        Chassis Device
    Aux Firmware Rev Info     :
        0x00
        0x00
        0x00
        0x00

    For the data shown above, the following dictionary will be returned.
    mc_info:
      [device_id]:                       0
      [device_revision]:                 0
      [firmware_revision]:               2.01
      [ipmi_version]:                    2.0
      [manufacturer_id]:                 42817
      [manufacturer_name]:               Unknown (0xA741)
      [product_id]:                      16975 (0x424f)
      [product_name]:                    Unknown (0x424F)
      [device_available]:                yes
      [provides_device_sdrs]:            yes
      [additional_device_support]:
        [additional_device_support][0]:  Sensor Device
        [additional_device_support][1]:  SEL Device
        [additional_device_support][2]:  FRU Inventory Device
        [additional_device_support][3]:  Chassis Device
      [aux_firmware_rev_info]:
        [aux_firmware_rev_info][0]:      0x00
        [aux_firmware_rev_info][1]:      0x00
        [aux_firmware_rev_info][2]:      0x00
        [aux_firmware_rev_info][3]:      0x00
    """

    status, ret_values = \
        grk.run_key_u("Run IPMI Standard Command  mc info")
    result = vf.key_value_outbuf_to_dict(ret_values, process_indent=1)

    return result


def get_sdr_info():
    r"""
    Get IPMI sdr info data and return it as a dictionary.

    The data is obtained by issuing the IPMI "sdr info" command.  An
    example is shown below:

    SDR Version                         : 0x51
    Record Count                        : 216
    Free Space                          : unspecified
    Most recent Addition                :
    Most recent Erase                   :
    SDR overflow                        : no
    SDR Repository Update Support       : unspecified
    Delete SDR supported                : no
    Partial Add SDR supported           : no
    Reserve SDR repository supported    : no
    SDR Repository Alloc info supported : no

    For the data shown above, the following dictionary will be returned.
    mc_info:

      [sdr_version]:                         0x51
      [record_Count]:                        216
      [free_space]:                          unspecified
      [most_recent_addition]:
      [most_recent_erase]:
      [sdr_overflow]:                        no
      [sdr_repository_update_support]:       unspecified
      [delete_sdr_supported]:                no
      [partial_add_sdr_supported]:           no
      [reserve_sdr_repository_supported]:    no
      [sdr_repository_alloc_info_supported]: no
    """

    status, ret_values = \
        grk.run_key_u("Run IPMI Standard Command  sdr info")
    result = vf.key_value_outbuf_to_dict(ret_values, process_indent=1)

    return result