1#!/usr/bin/env python
2
3r"""
4Companion file to utils.robot.
5"""
6
7import gen_print as gp
8import gen_robot_keyword as grk
9import bmc_ssh_utils as bsu
10import var_funcs as vf
11from robot.libraries.BuiltIn import BuiltIn
12from robot.libraries import DateTime
13try:
14    from robot.utils import DotDict
15except ImportError:
16    pass
17import collections
18
19
20def set_power_policy_method():
21    r"""
22    Set the global bmc_power_policy_method to either 'Old' or 'New'.
23
24    The power policy data has moved from an 'org' location to an 'xyz'
25    location.  This keyword will determine whether the new method of getting
26    the power policy is valid and will set the global bmc_power_policy_method
27    variable accordingly.  If power_policy_setup is already set (by a prior
28    call to this function), this keyword will simply return.
29
30    If bmc_power_policy_method is "Old", this function will adjust the global
31    policy variables from data/variables.py: RESTORE_LAST_STATE,
32    ALWAYS_POWER_ON, ALWAYS_POWER_OFF.
33    """
34
35    # Retrieve global variables.
36    power_policy_setup = \
37        int(BuiltIn().get_variable_value("${power_policy_setup}",
38                                         default=0))
39    bmc_power_policy_method = \
40        BuiltIn().get_variable_value("${bmc_power_policy_method}",
41                                     default=0)
42    gp.dpvar(power_policy_setup)
43
44    # If this function has already been run once, we need not continue.
45    if power_policy_setup:
46        return
47
48    gp.dpvar(bmc_power_policy_method, 1)
49
50    # The user has not set bmc_power_policy_method via a -v parm so we will
51    # determine what it should be.
52    if bmc_power_policy_method == "":
53        status, ret_values = grk.run_key_u("New Get Power Policy", ignore=1)
54        if status == 'PASS':
55            bmc_power_policy_method = 'New'
56        else:
57            bmc_power_policy_method = 'Old'
58
59    gp.qpvar(bmc_power_policy_method)
60    # For old style, we will rewrite these global variable settings to old
61    # values.
62    if bmc_power_policy_method == "Old":
63        BuiltIn().set_global_variable("${RESTORE_LAST_STATE}",
64                                      "RESTORE_LAST_STATE")
65        BuiltIn().set_global_variable("${ALWAYS_POWER_ON}",
66                                      "ALWAYS_POWER_ON")
67        BuiltIn().set_global_variable("${ALWAYS_POWER_OFF}",
68                                      "ALWAYS_POWER_OFF")
69
70    # Set global variables to control subsequent calls to this function.
71    BuiltIn().set_global_variable("${bmc_power_policy_method}",
72                                  bmc_power_policy_method)
73    BuiltIn().set_global_variable("${power_policy_setup}", 1)
74
75
76def translate_power_policy_value(policy):
77    r"""
78    Translate the policy value and return the result.
79
80    Using old style functions, callers might call like this with a hard-
81    code value for policy:
82
83    Set BMC Power Policy  ALWAYS_POWER_OFF
84
85    This function will get the value of the corresponding global variable (if
86    it exists) and return it.
87
88    This will allow the old style call to still work on systems using the new
89    method of storing the policy value.
90    """
91
92    valid_power_policy_vars = \
93        BuiltIn().get_variable_value("${valid_power_policy_vars}")
94
95    if policy not in valid_power_policy_vars:
96        return policy
97
98    status, ret_values = grk.run_key_u("Get Variable Value  ${" + policy + "}",
99                                       quiet=1)
100    return ret_values
101
102
103def get_bmc_date_time():
104    r"""
105    Get date/time info from BMC and return as a dictionary.
106
107    Example of dictionary data returned by this keyword.
108    time_dict:
109      [local_time]:               Fri 2017-11-03 152756 UTC
110      [local_time_seconds]:       1509740876
111      [universal_time]:           Fri 2017-11-03 152756 UTC
112      [universal_time_seconds]:   1509740876
113      [rtc_time]:                 Fri 2016-05-20 163403
114      [rtc_time_seconds]:         1463780043
115      [time_zone]:                n/a (UTC, +0000)
116      [network_time_on]:          yes
117      [ntp_synchronized]:         no
118      [rtc_in_local_tz]:          no
119    """
120
121    out_buf, stderr, rc = bsu.bmc_execute_command('timedatectl')
122    # Example of output returned by call to timedatectl:
123    #       Local time: Fri 2017-11-03 15:27:56 UTC
124    #   Universal time: Fri 2017-11-03 15:27:56 UTC
125    #         RTC time: Fri 2016-05-20 16:34:03
126    #        Time zone: n/a (UTC, +0000)
127    #  Network time on: yes
128    # NTP synchronized: no
129    #  RTC in local TZ: no
130
131    # Convert the out_buf to a dictionary.
132    initial_time_dict = vf.key_value_outbuf_to_dict(out_buf)
133
134    # For each "_time" entry in the dictionary, we will create a corresponding
135    # "_time_seconds" entry.  We create a new dictionary so that the entries
136    # are kept in a nice order for printing.
137    try:
138        result_time_dict = collections.OrderedDict()
139    except AttributeError:
140        result_time_dict = DotDict()
141
142    for key, value in initial_time_dict.items():
143        result_time_dict[key] = value
144        if not key.endswith("_time"):
145            continue
146        result_time_dict[key + '_seconds'] = \
147            int(DateTime.convert_date(value, result_format='epoch'))
148
149    return result_time_dict
150
151
152def get_bmc_df(df_parm_string=""):
153    r"""
154    Get df report from BMC and return as a report "object".
155
156    A df report object is a list where each entry is a dictionary whose keys
157    are the field names from the first entry in report_list.
158
159    Example df report object:
160
161    df_report:
162      df_report[0]:
163        [filesystem]:    dev
164        [1k-blocks]:     247120
165        [used]:          0
166        [available]:     247120
167        [use%]:          0%
168        [mounted]:       /dev
169      df_report[1]:
170        [filesystem]:    dev
171        [1k-blocks]:     247120
172        [used]:          0
173        [available]:     247120
174        [use%]:          0%
175        [mounted]:       /dev
176
177.   Description of argument(s):
178    df_parm_string  A string containing valid df command parms (e.g.
179                    "-h /var").
180    """
181
182    out_buf, stderr, rc = bsu.bmc_execute_command("df " + df_parm_string)
183    return vf.outbuf_to_report(out_buf)
184
185
186def get_sbe():
187    r"""
188    Return CFAM value which contains such things as SBE side bit.
189    """
190
191    cmd_buf = "pdbg -d p9w -p0 getcfam 0x2808 | sed -re 's/.* = //g'"
192    out_buf, stderr, rc = bsu.bmc_execute_command(cmd_buf)
193
194    return int(out_buf, 16)
195
196
197def compare_mac_address(sys_mac_addr, user_mac_addr):
198    r"""
199    Return 1 if the MAC value matched, otherwise 0.
200
201.   Description of argument(s):
202    sys_mac_addr   A valid system MAC string (e.g. "70:e2:84:14:2a:08")
203    user_mac_addr  A user provided MAC string (e.g. "70:e2:84:14:2a:08")
204    """
205
206    index = 0
207    # Example: ['70', 'e2', '84', '14', '2a', '08']
208    mac_list = user_mac_addr.split(":")
209    for item in sys_mac_addr.split(":"):
210        if int(item, 16) == int(mac_list[index], 16):
211            index = index + 1
212            continue
213        return 0
214
215    return 1
216
217
218def get_os_ethtool(interface_name):
219    r"""
220    Get OS 'ethtool' output for the given interface_name and return it as a
221    dictionary.
222
223    Settings for enP52p1s0f0:
224          Supported ports: [ TP ]
225          Supported link modes:   10baseT/Half 10baseT/Full
226                                  100baseT/Half 100baseT/Full
227                                  1000baseT/Half 1000baseT/Full
228          Supported pause frame use: No
229          Supports auto-negotiation: Yes
230          Supported FEC modes: Not reported
231          Advertised link modes:  10baseT/Half 10baseT/Full
232                                  100baseT/Half 100baseT/Full
233                                  1000baseT/Half 1000baseT/Full
234          Advertised pause frame use: Symmetric
235          Advertised auto-negotiation: Yes
236          Advertised FEC modes: Not reported
237          Speed: Unknown!
238          Duplex: Unknown! (255)
239          Port: Twisted Pair
240          PHYAD: 1
241          Transceiver: internal
242          Auto-negotiation: on
243          MDI-X: Unknown
244          Supports Wake-on: g
245          Wake-on: g
246          Current message level: 0x000000ff (255)
247                                 drv probe link timer ifdown ifup rx_err tx_err
248          Link detected: no
249
250    Given that data, this function will return the following dictionary.
251
252    ethtool_dict:
253      [supported_ports]:             [ TP ]
254      [supported_link_modes]:
255        [supported_link_modes][0]:   10baseT/Half 10baseT/Full
256        [supported_link_modes][1]:   100baseT/Half 100baseT/Full
257        [supported_link_modes][2]:   1000baseT/Half 1000baseT/Full
258      [supported_pause_frame_use]:   No
259      [supports_auto-negotiation]:   Yes
260      [supported_fec_modes]:         Not reported
261      [advertised_link_modes]:
262        [advertised_link_modes][0]:  10baseT/Half 10baseT/Full
263        [advertised_link_modes][1]:  100baseT/Half 100baseT/Full
264        [advertised_link_modes][2]:  1000baseT/Half 1000baseT/Full
265      [advertised_pause_frame_use]:  Symmetric
266      [advertised_auto-negotiation]: Yes
267      [advertised_fec_modes]:        Not reported
268      [speed]:                       Unknown!
269      [duplex]:                      Unknown! (255)
270      [port]:                        Twisted Pair
271      [phyad]:                       1
272      [transceiver]:                 internal
273      [auto-negotiation]:            on
274      [mdi-x]:                       Unknown
275      [supports_wake-on]:            g
276      [wake-on]:                     g
277      [current_message_level]:       0x000000ff (255)
278      [drv_probe_link_timer_ifdown_ifup_rx_err_tx_err]:<blank>
279      [link_detected]:               no
280    """
281
282    # Using sed and tail to massage the data a bit before running
283    # key_value_outbuf_to_dict.
284    cmd_buf = "ethtool " + interface_name +\
285        " | sed -re 's/(.* link modes:)(.*)/\\1\\n\\2/g' | tail -n +2"
286    stdout, stderr, rc = bsu.os_execute_command(cmd_buf)
287    result = vf.key_value_outbuf_to_dict(stdout, process_indent=1, strip=" \t")
288
289    return result
290