1#!/usr/bin/env python
2
3r"""
4Provide useful ipmi functions.
5"""
6
7import re
8import gen_print as gp
9import gen_misc as gm
10import gen_robot_keyword as grk
11import gen_robot_utils as gru
12import bmc_ssh_utils as bsu
13import var_funcs as vf
14import tempfile
15gru.my_import_resource("ipmi_client.robot")
16from robot.libraries.BuiltIn import BuiltIn
17
18
19def get_sol_info():
20    r"""
21    Get all SOL info and return it as a dictionary.
22
23    Example use:
24
25    Robot code:
26    ${sol_info}=  get_sol_info
27    Rpvars  sol_info
28
29    Output:
30    sol_info:
31      sol_info[Info]:                                SOL parameter 'Payload Channel (7)' not supported - defaulting to 0x0e
32      sol_info[Character Send Threshold]:            1
33      sol_info[Force Authentication]:                true
34      sol_info[Privilege Level]:                     USER
35      sol_info[Set in progress]:                     set-complete
36      sol_info[Retry Interval (ms)]:                 100
37      sol_info[Non-Volatile Bit Rate (kbps)]:        IPMI-Over-Serial-Setting
38      sol_info[Character Accumulate Level (ms)]:     100
39      sol_info[Enabled]:                             true
40      sol_info[Volatile Bit Rate (kbps)]:            IPMI-Over-Serial-Setting
41      sol_info[Payload Channel]:                     14 (0x0e)
42      sol_info[Payload Port]:                        623
43      sol_info[Force Encryption]:                    true
44      sol_info[Retry Count]:                         7
45    """
46
47    status, ret_values = grk.run_key_u("Run IPMI Standard Command  sol info")
48
49    # Create temp file path.
50    temp = tempfile.NamedTemporaryFile()
51    temp_file_path = temp.name
52
53    # Write sol info to temp file path.
54    text_file = open(temp_file_path, "w")
55    text_file.write(ret_values)
56    text_file.close()
57
58    # Use my_parm_file to interpret data.
59    sol_info = gm.my_parm_file(temp_file_path)
60
61    return sol_info
62
63
64def set_sol_setting(setting_name, setting_value):
65    r"""
66    Set SOL setting with given value.
67
68    # Description of argument(s):
69    # setting_name    SOL setting which needs to be set (e.g. "retry-count").
70    # setting_value   Value which needs to be set (e.g. "7").
71    """
72
73    status, ret_values = grk.run_key_u("Run IPMI Standard Command  sol set " +
74                                       setting_name + " " + setting_value)
75
76    return status
77
78
79def get_lan_print_dict():
80    r"""
81    Get IPMI 'lan print' output and return it as a dictionary.
82
83    Here is an example of the IPMI lan print output:
84
85    Set in Progress         : Set Complete
86    Auth Type Support       : MD5
87    Auth Type Enable        : Callback : MD5
88                            : User     : MD5
89                            : Operator : MD5
90                            : Admin    : MD5
91                            : OEM      : MD5
92    IP Address Source       : Static Address
93    IP Address              : x.x.x.x
94    Subnet Mask             : x.x.x.x
95    MAC Address             : xx:xx:xx:xx:xx:xx
96    Default Gateway IP      : x.x.x.x
97    802.1q VLAN ID          : Disabled
98    Cipher Suite Priv Max   : Not Available
99    Bad Password Threshold  : Not Available
100
101    Given that data, this function will return the following dictionary.
102
103    lan_print_dict:
104      [Set in Progress]:                              Set Complete
105      [Auth Type Support]:                            MD5
106      [Auth Type Enable]:
107        [Callback]:                                   MD5
108        [User]:                                       MD5
109        [Operator]:                                   MD5
110        [Admin]:                                      MD5
111        [OEM]:                                        MD5
112      [IP Address Source]:                            Static Address
113      [IP Address]:                                   x.x.x.x
114      [Subnet Mask]:                                  x.x.x.x
115      [MAC Address]:                                  xx:xx:xx:xx:xx:xx
116      [Default Gateway IP]:                           x.x.x.x
117      [802.1q VLAN ID]:                               Disabled
118      [Cipher Suite Priv Max]:                        Not Available
119      [Bad Password Threshold]:                       Not Available
120
121    """
122
123    IPMI_INBAND_CMD = BuiltIn().get_variable_value("${IPMI_INBAND_CMD}")
124
125    # Notice in the example of data above that 'Auth Type Enable' needs some
126    # special processing.  We essentially want to isolate its data and remove
127    # the 'Auth Type Enable' string so that key_value_outbuf_to_dict can
128    # process it as a sub-dictionary.
129    cmd_buf = IPMI_INBAND_CMD + " lan print | grep -E '^(Auth Type Enable)" +\
130        "?[ ]+: ' | sed -re 's/^(Auth Type Enable)?[ ]+: //g'"
131    stdout1, stderr, rc = bsu.os_execute_command(cmd_buf)
132
133    # Now get the remainder of the data and exclude the lines with no field
134    # names (i.e. the 'Auth Type Enable' sub-fields).
135    cmd_buf = IPMI_INBAND_CMD + " lan print | grep -E -v '^[ ]+: '"
136    stdout2, stderr, rc = bsu.os_execute_command(cmd_buf)
137
138    # Make auth_type_enable_dict sub-dictionary...
139    auth_type_enable_dict = vf.key_value_outbuf_to_dict(stdout1, to_lower=0,
140                                                        underscores=0)
141
142    # Create the lan_print_dict...
143    lan_print_dict = vf.key_value_outbuf_to_dict(stdout2, to_lower=0,
144                                                 underscores=0)
145    # Re-assign 'Auth Type Enable' to contain the auth_type_enable_dict.
146    lan_print_dict['Auth Type Enable'] = auth_type_enable_dict
147
148    return lan_print_dict
149
150
151def get_ipmi_power_reading(strip_watts=1):
152    r"""
153    Get IPMI power reading data and return it as a dictionary.
154
155    The data is obtained by issuing the IPMI "power reading" command.  An
156    example is shown below:
157
158    Instantaneous power reading:                   234 Watts
159    Minimum during sampling period:                234 Watts
160    Maximum during sampling period:                234 Watts
161    Average power reading over sample period:      234 Watts
162    IPMI timestamp:                           Thu Jan  1 00:00:00 1970
163    Sampling period:                          00000000 Seconds.
164    Power reading state is:                   deactivated
165
166    For the data shown above, the following dictionary will be returned.
167
168    result:
169      [instantaneous_power_reading]:              238 Watts
170      [minimum_during_sampling_period]:           238 Watts
171      [maximum_during_sampling_period]:           238 Watts
172      [average_power_reading_over_sample_period]: 238 Watts
173      [ipmi_timestamp]:                           Thu Jan  1 00:00:00 1970
174      [sampling_period]:                          00000000 Seconds.
175      [power_reading_state_is]:                   deactivated
176
177    Description of argument(s):
178    strip_watts  Strip all dictionary values of the trailing " Watts"
179                 substring.
180    """
181
182    status, ret_values = \
183        grk.run_key_u("Run IPMI Standard Command  dcmi power reading")
184    result = vf.key_value_outbuf_to_dict(ret_values)
185
186    if strip_watts:
187        result.update((k, re.sub(' Watts$', '', v)) for k, v in result.items())
188
189    return result
190
191
192def get_mc_info():
193    r"""
194    Get IPMI mc info data and return it as a dictionary.
195
196    The data is obtained by issuing the IPMI "mc info" command.  An
197    example is shown below:
198
199    Device ID                 : 0
200    Device Revision           : 0
201    Firmware Revision         : 2.01
202    IPMI Version              : 2.0
203    Manufacturer ID           : 42817
204    Manufacturer Name         : Unknown (0xA741)
205    Product ID                : 16975 (0x424f)
206    Product Name              : Unknown (0x424F)
207    Device Available          : yes
208    Provides Device SDRs      : yes
209    Additional Device Support :
210        Sensor Device
211        SEL Device
212        FRU Inventory Device
213        Chassis Device
214    Aux Firmware Rev Info     :
215        0x00
216        0x00
217        0x00
218        0x00
219
220    For the data shown above, the following dictionary will be returned.
221    mc_info:
222      [device_id]:                       0
223      [device_revision]:                 0
224      [firmware_revision]:               2.01
225      [ipmi_version]:                    2.0
226      [manufacturer_id]:                 42817
227      [manufacturer_name]:               Unknown (0xA741)
228      [product_id]:                      16975 (0x424f)
229      [product_name]:                    Unknown (0x424F)
230      [device_available]:                yes
231      [provides_device_sdrs]:            yes
232      [additional_device_support]:
233        [additional_device_support][0]:  Sensor Device
234        [additional_device_support][1]:  SEL Device
235        [additional_device_support][2]:  FRU Inventory Device
236        [additional_device_support][3]:  Chassis Device
237      [aux_firmware_rev_info]:
238        [aux_firmware_rev_info][0]:      0x00
239        [aux_firmware_rev_info][1]:      0x00
240        [aux_firmware_rev_info][2]:      0x00
241        [aux_firmware_rev_info][3]:      0x00
242    """
243
244    status, ret_values = \
245        grk.run_key_u("Run IPMI Standard Command  mc info")
246    result = vf.key_value_outbuf_to_dict(ret_values, process_indent=1)
247
248    return result
249
250
251def get_sdr_info():
252    r"""
253    Get IPMI sdr info data and return it as a dictionary.
254
255    The data is obtained by issuing the IPMI "sdr info" command.  An
256    example is shown below:
257
258    SDR Version                         : 0x51
259    Record Count                        : 216
260    Free Space                          : unspecified
261    Most recent Addition                :
262    Most recent Erase                   :
263    SDR overflow                        : no
264    SDR Repository Update Support       : unspecified
265    Delete SDR supported                : no
266    Partial Add SDR supported           : no
267    Reserve SDR repository supported    : no
268    SDR Repository Alloc info supported : no
269
270    For the data shown above, the following dictionary will be returned.
271    mc_info:
272
273      [sdr_version]:                         0x51
274      [record_Count]:                        216
275      [free_space]:                          unspecified
276      [most_recent_addition]:
277      [most_recent_erase]:
278      [sdr_overflow]:                        no
279      [sdr_repository_update_support]:       unspecified
280      [delete_sdr_supported]:                no
281      [partial_add_sdr_supported]:           no
282      [reserve_sdr_repository_supported]:    no
283      [sdr_repository_alloc_info_supported]: no
284    """
285
286    status, ret_values = \
287        grk.run_key_u("Run IPMI Standard Command  sdr info")
288    result = vf.key_value_outbuf_to_dict(ret_values, process_indent=1)
289
290    return result
291
292
293def get_aux_version(version_id):
294    r"""
295    Get IPMI Aux version info data and return it.
296
297    Description of argument(s):
298    version_id    The data is obtained by from BMC /etc/os-release
299                  (e.g. "xxx-v2.1-438-g0030304-r3-gfea8585").
300
301    In the prior example, the 3rd field is "438" is the commit version and
302    the 5th field is "r3" and value "3" is the release version.
303
304    Aux version return from this function 4380003.
305    """
306
307    # Commit version.
308    count = re.findall("-(\d{1,4})-", version_id)
309
310    # Release version.
311    release = re.findall("-r(\d{1,4})", version_id)
312    if release:
313        aux_version = count[0] + "{0:0>4}".format(release[0])
314    else:
315        aux_version = count[0] + "0000"
316
317    return aux_version
318