1#!/usr/bin/env python3
2
3r"""
4Provide useful ipmi functions.
5"""
6
7import re
8import gen_print as gp
9import gen_misc as gm
10import gen_cmd as gc
11import gen_robot_keyword as grk
12import gen_robot_utils as gru
13import bmc_ssh_utils as bsu
14import var_funcs as vf
15import ipmi_client as ic
16import tempfile
17import json
18from robot.libraries.BuiltIn import BuiltIn
19
20gru.my_import_resource("ipmi_client.robot")
21
22
23def get_sol_info():
24    r"""
25    Get all SOL info and return it as a dictionary.
26
27    Example use:
28
29    Robot code:
30    ${sol_info}=  get_sol_info
31    Rpvars  sol_info
32
33    Output:
34    sol_info:
35      sol_info[Info]:                                SOL parameter 'Payload Channel (7)'
36                                                     not supported - defaulting to 0x0e
37      sol_info[Character Send Threshold]:            1
38      sol_info[Force Authentication]:                true
39      sol_info[Privilege Level]:                     USER
40      sol_info[Set in progress]:                     set-complete
41      sol_info[Retry Interval (ms)]:                 100
42      sol_info[Non-Volatile Bit Rate (kbps)]:        IPMI-Over-Serial-Setting
43      sol_info[Character Accumulate Level (ms)]:     100
44      sol_info[Enabled]:                             true
45      sol_info[Volatile Bit Rate (kbps)]:            IPMI-Over-Serial-Setting
46      sol_info[Payload Channel]:                     14 (0x0e)
47      sol_info[Payload Port]:                        623
48      sol_info[Force Encryption]:                    true
49      sol_info[Retry Count]:                         7
50    """
51
52    status, ret_values = grk.run_key_u("Run IPMI Standard Command  sol info")
53
54    # Create temp file path.
55    temp = tempfile.NamedTemporaryFile()
56    temp_file_path = temp.name
57
58    # Write sol info to temp file path.
59    text_file = open(temp_file_path, "w")
60    text_file.write(ret_values)
61    text_file.close()
62
63    # Use my_parm_file to interpret data.
64    sol_info = gm.my_parm_file(temp_file_path)
65
66    return sol_info
67
68
69def set_sol_setting(setting_name, setting_value):
70    r"""
71    Set SOL setting with given value.
72
73    # Description of argument(s):
74    # setting_name                  SOL setting which needs to be set (e.g.
75    #                               "retry-count").
76    # setting_value                 Value which needs to be set (e.g. "7").
77    """
78
79    status, ret_values = grk.run_key_u("Run IPMI Standard Command  sol set "
80                                       + setting_name + " " + setting_value)
81
82    return status
83
84
85def execute_ipmi_cmd(cmd_string,
86                     ipmi_cmd_type='inband',
87                     print_output=1,
88                     ignore_err=0,
89                     **options):
90    r"""
91    Run the given command string as an IPMI command and return the stdout,
92    stderr and the return code.
93
94    Description of argument(s):
95    cmd_string                      The command string to be run as an IPMI
96                                    command.
97    ipmi_cmd_type                   'inband' or 'external'.
98    print_output                    If this is set, this function will print
99                                    the stdout/stderr generated by
100                                    the IPMI command.
101    ignore_err                      Ignore error means that a failure
102                                    encountered by running the command
103                                    string will not be raised as a python
104                                    exception.
105    options                         These are passed directly to the
106                                    create_ipmi_ext_command_string function.
107                                    See that function's prolog for details.
108    """
109
110    if ipmi_cmd_type == 'inband':
111        IPMI_INBAND_CMD = BuiltIn().get_variable_value("${IPMI_INBAND_CMD}")
112        cmd_buf = IPMI_INBAND_CMD + " " + cmd_string
113        return bsu.os_execute_command(cmd_buf,
114                                      print_out=print_output,
115                                      ignore_err=ignore_err)
116
117    if ipmi_cmd_type == 'external':
118        cmd_buf = ic.create_ipmi_ext_command_string(cmd_string, **options)
119        rc, stdout, stderr = gc.shell_cmd(cmd_buf,
120                                          print_output=print_output,
121                                          ignore_err=ignore_err,
122                                          return_stderr=1)
123        return stdout, stderr, rc
124
125
126def get_lan_print_dict(channel_number='', ipmi_cmd_type='external'):
127    r"""
128    Get IPMI 'lan print' output and return it as a dictionary.
129
130    Here is an example of the IPMI lan print output:
131
132    Set in Progress         : Set Complete
133    Auth Type Support       : MD5
134    Auth Type Enable        : Callback : MD5
135                            : User     : MD5
136                            : Operator : MD5
137                            : Admin    : MD5
138                            : OEM      : MD5
139    IP Address Source       : Static Address
140    IP Address              : x.x.x.x
141    Subnet Mask             : x.x.x.x
142    MAC Address             : xx:xx:xx:xx:xx:xx
143    Default Gateway IP      : x.x.x.x
144    802.1q VLAN ID          : Disabled
145    Cipher Suite Priv Max   : Not Available
146    Bad Password Threshold  : Not Available
147
148    Given that data, this function will return the following dictionary.
149
150    lan_print_dict:
151      [Set in Progress]:                              Set Complete
152      [Auth Type Support]:                            MD5
153      [Auth Type Enable]:
154        [Callback]:                                   MD5
155        [User]:                                       MD5
156        [Operator]:                                   MD5
157        [Admin]:                                      MD5
158        [OEM]:                                        MD5
159      [IP Address Source]:                            Static Address
160      [IP Address]:                                   x.x.x.x
161      [Subnet Mask]:                                  x.x.x.x
162      [MAC Address]:                                  xx:xx:xx:xx:xx:xx
163      [Default Gateway IP]:                           x.x.x.x
164      [802.1q VLAN ID]:                               Disabled
165      [Cipher Suite Priv Max]:                        Not Available
166      [Bad Password Threshold]:                       Not Available
167
168    Description of argument(s):
169    ipmi_cmd_type                   The type of ipmi command to use (e.g.
170                                    'inband', 'external').
171    """
172
173    channel_number = str(channel_number)
174    # Notice in the example of data above that 'Auth Type Enable' needs some
175    # special processing.  We essentially want to isolate its data and remove
176    # the 'Auth Type Enable' string so that key_value_outbuf_to_dict can
177    # process it as a sub-dictionary.
178    cmd_buf = "lan print " + channel_number + " | grep -E '^(Auth Type Enable)" +\
179        "?[ ]+: ' | sed -re 's/^(Auth Type Enable)?[ ]+: //g'"
180    stdout1, stderr, rc = execute_ipmi_cmd(cmd_buf, ipmi_cmd_type,
181                                           print_output=0)
182
183    # Now get the remainder of the data and exclude the lines with no field
184    # names (i.e. the 'Auth Type Enable' sub-fields).
185    cmd_buf = "lan print " + channel_number + " | grep -E -v '^[ ]+: '"
186    stdout2, stderr, rc = execute_ipmi_cmd(cmd_buf, ipmi_cmd_type,
187                                           print_output=0)
188
189    # Make auth_type_enable_dict sub-dictionary...
190    auth_type_enable_dict = vf.key_value_outbuf_to_dict(stdout1, to_lower=0,
191                                                        underscores=0)
192
193    # Create the lan_print_dict...
194    lan_print_dict = vf.key_value_outbuf_to_dict(stdout2, to_lower=0,
195                                                 underscores=0)
196    # Re-assign 'Auth Type Enable' to contain the auth_type_enable_dict.
197    lan_print_dict['Auth Type Enable'] = auth_type_enable_dict
198
199    return lan_print_dict
200
201
202def get_ipmi_power_reading(strip_watts=1):
203    r"""
204    Get IPMI power reading data and return it as a dictionary.
205
206    The data is obtained by issuing the IPMI "power reading" command.  An
207    example is shown below:
208
209    Instantaneous power reading:                   234 Watts
210    Minimum during sampling period:                234 Watts
211    Maximum during sampling period:                234 Watts
212    Average power reading over sample period:      234 Watts
213    IPMI timestamp:                           Thu Jan  1 00:00:00 1970
214    Sampling period:                          00000000 Seconds.
215    Power reading state is:                   deactivated
216
217    For the data shown above, the following dictionary will be returned.
218
219    result:
220      [instantaneous_power_reading]:              238 Watts
221      [minimum_during_sampling_period]:           238 Watts
222      [maximum_during_sampling_period]:           238 Watts
223      [average_power_reading_over_sample_period]: 238 Watts
224      [ipmi_timestamp]:                           Thu Jan  1 00:00:00 1970
225      [sampling_period]:                          00000000 Seconds.
226      [power_reading_state_is]:                   deactivated
227
228    Description of argument(s):
229    strip_watts                     Strip all dictionary values of the
230                                    trailing " Watts" substring.
231    """
232
233    status, ret_values = \
234        grk.run_key_u("Run IPMI Standard Command  dcmi power reading")
235    result = vf.key_value_outbuf_to_dict(ret_values)
236
237    if strip_watts:
238        result.update((k, re.sub(' Watts$', '', v)) for k, v in result.items())
239
240    return result
241
242
243def get_mc_info():
244    r"""
245    Get IPMI mc info data and return it as a dictionary.
246
247    The data is obtained by issuing the IPMI "mc info" command.  An
248    example is shown below:
249
250    Device ID                 : 0
251    Device Revision           : 0
252    Firmware Revision         : 2.01
253    IPMI Version              : 2.0
254    Manufacturer ID           : 42817
255    Manufacturer Name         : Unknown (0xA741)
256    Product ID                : 16975 (0x424f)
257    Product Name              : Unknown (0x424F)
258    Device Available          : yes
259    Provides Device SDRs      : yes
260    Additional Device Support :
261        Sensor Device
262        SEL Device
263        FRU Inventory Device
264        Chassis Device
265    Aux Firmware Rev Info     :
266        0x00
267        0x00
268        0x00
269        0x00
270
271    For the data shown above, the following dictionary will be returned.
272    mc_info:
273      [device_id]:                       0
274      [device_revision]:                 0
275      [firmware_revision]:               2.01
276      [ipmi_version]:                    2.0
277      [manufacturer_id]:                 42817
278      [manufacturer_name]:               Unknown (0xA741)
279      [product_id]:                      16975 (0x424f)
280      [product_name]:                    Unknown (0x424F)
281      [device_available]:                yes
282      [provides_device_sdrs]:            yes
283      [additional_device_support]:
284        [additional_device_support][0]:  Sensor Device
285        [additional_device_support][1]:  SEL Device
286        [additional_device_support][2]:  FRU Inventory Device
287        [additional_device_support][3]:  Chassis Device
288      [aux_firmware_rev_info]:
289        [aux_firmware_rev_info][0]:      0x00
290        [aux_firmware_rev_info][1]:      0x00
291        [aux_firmware_rev_info][2]:      0x00
292        [aux_firmware_rev_info][3]:      0x00
293    """
294
295    status, ret_values = \
296        grk.run_key_u("Run IPMI Standard Command  mc info")
297    result = vf.key_value_outbuf_to_dict(ret_values, process_indent=1)
298
299    return result
300
301
302def get_sdr_info():
303    r"""
304    Get IPMI sdr info data and return it as a dictionary.
305
306    The data is obtained by issuing the IPMI "sdr info" command.  An
307    example is shown below:
308
309    SDR Version                         : 0x51
310    Record Count                        : 216
311    Free Space                          : unspecified
312    Most recent Addition                :
313    Most recent Erase                   :
314    SDR overflow                        : no
315    SDR Repository Update Support       : unspecified
316    Delete SDR supported                : no
317    Partial Add SDR supported           : no
318    Reserve SDR repository supported    : no
319    SDR Repository Alloc info supported : no
320
321    For the data shown above, the following dictionary will be returned.
322    mc_info:
323
324      [sdr_version]:                         0x51
325      [record_Count]:                        216
326      [free_space]:                          unspecified
327      [most_recent_addition]:
328      [most_recent_erase]:
329      [sdr_overflow]:                        no
330      [sdr_repository_update_support]:       unspecified
331      [delete_sdr_supported]:                no
332      [partial_add_sdr_supported]:           no
333      [reserve_sdr_repository_supported]:    no
334      [sdr_repository_alloc_info_supported]: no
335    """
336
337    status, ret_values = \
338        grk.run_key_u("Run IPMI Standard Command  sdr info")
339    result = vf.key_value_outbuf_to_dict(ret_values, process_indent=1)
340
341    return result
342
343
344def get_aux_version(version_id):
345    r"""
346    Get IPMI Aux version info data and return it.
347
348    Description of argument(s):
349    version_id                      The data is obtained by from BMC
350                                    /etc/os-release
351                                    (e.g. "xxx-v2.1-438-g0030304-r3-gfea8585").
352
353    In the prior example, the 3rd field is "438" is the commit version and
354    the 5th field is "r3" and value "3" is the release version.
355
356    Aux version return from this function 4380003.
357    """
358
359    # Commit version.
360    count = re.findall("-(\\d{1,4})-", version_id)
361
362    # Release version.
363    release = re.findall("-r(\\d{1,4})", version_id)
364    if release:
365        aux_version = count[0] + "{0:0>4}".format(release[0])
366    else:
367        aux_version = count[0] + "0000"
368
369    return aux_version
370
371
372def get_fru_info():
373    r"""
374    Get fru info and return it as a list of dictionaries.
375
376    The data is obtained by issuing the IPMI "fru print -N 50" command.  An
377    example is shown below:
378
379    FRU Device Description : Builtin FRU Device (ID 0)
380     Device not present (Unspecified error)
381
382    FRU Device Description : cpu0 (ID 1)
383     Board Mfg Date        : Sun Dec 31 18:00:00 1995
384     Board Mfg             : <Manufacturer Name>
385     Board Product         : PROCESSOR MODULE
386     Board Serial          : YA1934315964
387     Board Part Number     : 02CY209
388
389    FRU Device Description : cpu1 (ID 2)
390     Board Mfg Date        : Sun Dec 31 18:00:00 1995
391     Board Mfg             : <Manufacturer Name>
392     Board Product         : PROCESSOR MODULE
393     Board Serial          : YA1934315965
394     Board Part Number     : 02CY209
395
396    For the data shown above, the following list of dictionaries will be
397    returned.
398
399    fru_obj:
400      fru_obj[0]:
401        [fru_device_description]:  Builtin FRU Device (ID 0)
402        [state]:                   Device not present (Unspecified error)
403      fru_obj[1]:
404        [fru_device_description]:  cpu0 (ID 1)
405        [board_mfg_date]:          Sun Dec 31 18:00:00 1995
406        [board_mfg]:               <Manufacturer Name>
407        [board_product]:           PROCESSOR MODULE
408        [board_serial]:            YA1934315964
409        [board_part_number]:       02CY209
410      fru_obj[2]:
411        [fru_device_description]:  cpu1 (ID 2)
412        [board_mfg_date]:          Sun Dec 31 18:00:00 1995
413        [board_mfg]:               <Manufacturer Name>
414        [board_product]:           PROCESSOR MODULE
415        [board_serial]:            YA1934315965
416        [board_part_number]:       02CY209
417    """
418
419    status, ret_values = \
420        grk.run_key_u("Run IPMI Standard Command  fru print -N 50")
421
422    # Manipulate the "Device not present" line to create a "state" key.
423    ret_values = re.sub("Device not present", "state : Device not present",
424                        ret_values)
425
426    return [vf.key_value_outbuf_to_dict(x) for x in re.split("\n\n",
427                                                             ret_values)]
428
429
430def get_component_fru_info(component='cpu',
431                           fru_objs=None):
432    r"""
433    Get fru info for the given component and return it as a list of
434    dictionaries.
435
436    This function calls upon get_fru_info and then filters out the unwanted
437    entries.  See get_fru_info's prolog for a layout of the data.
438
439    Description of argument(s):
440    component                       The component (e.g. "cpu", "dimm", etc.).
441    fru_objs                        A fru_objs list such as the one returned
442                                    by get_fru_info.  If this is None, then
443                                    this function will call get_fru_info to
444                                    obtain such a list.
445                                    Supplying this argument may improve
446                                    performance if this function is to be
447                                    called multiple times.
448    """
449
450    if fru_objs is None:
451        fru_objs = get_fru_info()
452    return\
453        [x for x in fru_objs
454         if re.match(component + '([0-9]+)? ', x['fru_device_description'])]
455
456
457def get_user_info(userid, channel_number=1):
458    r"""
459    Get user info using channel command and return it as a dictionary.
460
461    Description of argument(s):
462    userid          The userid (e.g. "1", "2", etc.).
463    channel_number  The user's channel number (e.g. "1").
464
465    Note: If userid is blank, this function will return a list of dictionaries.  Each list entry represents
466    one userid record.
467
468    The data is obtained by issuing the IPMI "channel getaccess" command.  An
469    example is shown below for user id 1 and channel number 1.
470
471    Maximum User IDs     : 15
472    Enabled User IDs     : 1
473    User ID              : 1
474    User Name            : root
475    Fixed Name           : No
476    Access Available     : callback
477    Link Authentication  : enabled
478    IPMI Messaging       : enabled
479    Privilege Level      : ADMINISTRATOR
480    Enable Status        : enabled
481
482    For the data shown above, the following dictionary will be returned.
483
484    user_info:
485      [maximum_userids]:     15
486      [enabled_userids:      1
487      [userid]               1
488      [user_name]            root
489      [fixed_name]           No
490      [access_available]     callback
491      [link_authentication]  enabled
492      [ipmi_messaging]       enabled
493      [privilege_level]      ADMINISTRATOR
494      [enable_status]        enabled
495    """
496
497    status, ret_values = grk.run_key_u("Run IPMI Standard Command  channel getaccess "
498                                       + str(channel_number) + " " + str(userid))
499
500    if userid == "":
501        return vf.key_value_outbuf_to_dicts(ret_values, process_indent=1)
502    else:
503        return vf.key_value_outbuf_to_dict(ret_values, process_indent=1)
504
505
506def channel_getciphers_ipmi():
507
508    r"""
509    Run 'channel getciphers ipmi' command and return the result as a list of dictionaries.
510
511    Example robot code:
512    ${ipmi_channel_ciphers}=  Channel Getciphers IPMI
513    Rprint Vars  ipmi_channel_ciphers
514
515    Example output:
516    ipmi_channel_ciphers:
517      [0]:
518        [id]:                                         3
519        [iana]:                                       N/A
520        [auth_alg]:                                   hmac_sha1
521        [integrity_alg]:                              hmac_sha1_96
522        [confidentiality_alg]:                        aes_cbc_128
523      [1]:
524        [id]:                                         17
525        [iana]:                                       N/A
526        [auth_alg]:                                   hmac_sha256
527        [integrity_alg]:                              sha256_128
528        [confidentiality_alg]:                        aes_cbc_128
529    """
530
531    cmd_buf = "channel getciphers ipmi | sed -re 's/ Alg/_Alg/g'"
532    stdout, stderr, rc = execute_ipmi_cmd(cmd_buf, "external", print_output=0)
533    return vf.outbuf_to_report(stdout)
534
535
536def get_device_id_config():
537    r"""
538    Get the device id config data and return as a dictionary.
539
540    Example:
541
542    dev_id_config =  get_device_id_config()
543    print_vars(dev_id_config)
544
545    dev_id_config:
546        [manuf_id]:            7244
547        [addn_dev_support]:     141
548        [prod_id]:            16976
549        [aux]:                    0
550        [id]:                    32
551        [revision]:             129
552        [device_revision]:        1
553    """
554    stdout, stderr, rc = bsu.bmc_execute_command("cat /usr/share/ipmi-providers/dev_id.json")
555
556    result = json.loads(stdout)
557
558    # Create device revision field for the user.
559    # Reference IPMI specification v2.0 "Get Device ID Command"
560    # [7]   1 = device provides Device SDRs
561    #       0 = device does not provide Device SDRs
562    # [6:4] reserved. Return as 0.
563    # [3:0] Device Revision, binary encoded.
564
565    result['device_revision'] = result['revision'] & 0x0F
566
567    return result
568
569
570def get_chassis_status():
571    r"""
572    Get IPMI chassis status data and return it as a dictionary.
573
574    The data is obtained by issuing the IPMI "chassis status" command. An
575    example is shown below:
576
577    System Power              : off
578    Power Overload            : false
579    Power Interlock           : inactive
580    Main Power Fault          : false
581    Power Control Fault       : false
582    Power Restore Policy      : previous
583    Last Power Event          :
584    Chassis Intrusion         : inactive
585    Front-Panel Lockout       : inactive
586    Drive Fault               : false
587    Cooling/Fan Fault         : false
588    Sleep Button Disable      : not allowed
589    Diag Button Disable       : not allowed
590    Reset Button Disable      : not allowed
591    Power Button Disable      : allowed
592    Sleep Button Disabled     : false
593    Diag Button Disabled      : false
594    Reset Button Disabled     : false
595    Power Button Disabled     : false
596
597    For the data shown above, the following dictionary will be returned.
598
599    chassis_status:
600      [system_power]:                        off
601      [power_overload]:                      false
602      [power_interlock]:                     inactive
603      [main_power_fault]:                    false
604      [power_control_fault]:                 false
605      [power_restore_policy]:                previous
606      [last_power_event]:
607      [chassis_intrusion]:                   inactive
608      [front-panel_lockout]:                 inactive
609      [drive_fault]:                         false
610      [cooling/fan_fault]:                   false
611      [sleep_button_disable]:                not allowed
612      [diag_button_disable]:                 not allowed
613      [reset_button_disable]:                not allowed
614      [power_button_disable]:                allowed
615      [sleep_button_disabled]:               false
616      [diag_button_disabled]:                false
617      [reset_button_disabled]:               false
618      [power_button_disabled]:               false
619    """
620
621    status, ret_values = \
622        grk.run_key_u("Run IPMI Standard Command  chassis status")
623    result = vf.key_value_outbuf_to_dict(ret_values, process_indent=1)
624
625    return result
626
627
628def get_channel_info(channel_number=1):
629    r"""
630    Get the channel info and return as a dictionary.
631    Example:
632
633    channel_info:
634      [channel_0x2_info]:
635        [channel_medium_type]:                        802.3 LAN
636        [channel_protocol_type]:                      IPMB-1.0
637        [session_support]:                            multi-session
638        [active_session_count]:                       0
639        [protocol_vendor_id]:                         7154
640      [volatile(active)_settings]:
641        [alerting]:                                   enabled
642        [per-message_auth]:                           enabled
643        [user_level_auth]:                            enabled
644        [access_mode]:                                always available
645      [non-volatile_settings]:
646        [alerting]:                                   enabled
647        [per-message_auth]:                           enabled
648        [user_level_auth]:                            enabled
649        [access_mode]:                                always available
650    """
651
652    status, ret_values = \
653        grk.run_key_u("Run IPMI Standard Command  channel info " + str(channel_number))
654    key_var_list = list(filter(None, ret_values.split("\n")))
655    # To match the dict format, add a colon after 'Volatile(active) Settings' and 'Non-Volatile Settings'
656    # respectively.
657    key_var_list[6] = 'Volatile(active) Settings:'
658    key_var_list[11] = 'Non-Volatile Settings:'
659    result = vf.key_value_list_to_dict(key_var_list, process_indent=1)
660    return result
661
662
663def get_user_access_ipmi(channel_number=1):
664
665    r"""
666    Run 'user list [<channel number>]' command and return the result as a list of dictionaries.
667
668    Example robot code:
669    ${users_access}=  user list 1
670    Rprint Vars  users_access
671
672    Example output:
673    users:
674      [0]:
675        [id]:                                         1
676        [name]:                                       root
677        [callin]:                                     false
678        [link]:                                       true
679        [auth]:                                       true
680        [ipmi]:                                       ADMINISTRATOR
681      [1]:
682        [id]:                                         2
683        [name]:                                       axzIDwnz
684        [callin]:                                     true
685        [link]:                                       false
686        [auth]:                                       true
687        [ipmi]:                                       ADMINISTRATOR
688    """
689
690    cmd_buf = "user list " + str(channel_number)
691    stdout, stderr, rc = execute_ipmi_cmd(cmd_buf, "external", print_output=0)
692    return vf.outbuf_to_report(stdout)
693
694
695def get_channel_auth_capabilities(channel_number=1, privilege_level=4):
696    r"""
697    Get the channel authentication capabilities and return as a dictionary.
698
699    Example:
700
701    channel_auth_cap:
702        [channel_number]:                               2
703        [ipmi_v1.5__auth_types]:
704        [kg_status]:                                    default (all zeroes)
705        [per_message_authentication]:                   enabled
706        [user_level_authentication]:                    enabled
707        [non-null_user_names_exist]:                    yes
708        [null_user_names_exist]:                        no
709        [anonymous_login_enabled]:                      no
710        [channel_supports_ipmi_v1.5]:                   no
711        [channel_supports_ipmi_v2.0]:                   yes
712    """
713
714    status, ret_values = \
715        grk.run_key_u("Run IPMI Standard Command  channel authcap " + str(channel_number) + " "
716                      + str(privilege_level))
717    result = vf.key_value_outbuf_to_dict(ret_values, process_indent=1)
718
719    return result
720
721
722def fetch_date(date):
723    r"""
724    Removes prefix 0 in a date in given date
725
726    Example : 08/12/2021 then returns 8/12/2021
727    """
728
729    date = date.lstrip("0")
730    return date
731
732
733def fetch_added_sel_date(entry):
734    r"""
735    Split sel entry string with with | and join only the date with space
736
737    Example : If entry given is, "a | 02/14/2020 | 01:16:58 | Sensor_type #0x17 |  | Asserted"
738    Then the result will be "02/14/2020 01:16:58"
739    """
740
741    temp = entry.split(" | ")
742    date = temp[1] + " " + temp[2]
743    print(date)
744    return date
745
746
747def prefix_bytes(listx):
748    r"""
749    prefixes byte strings in list
750
751    Example:
752    ${listx} = ['01', '02', '03']
753    ${listx}=  Prefix Bytes  ${listx}
754    then,
755    ${listx}= ['0x01', '0x02', '0x03']
756
757    """
758
759    listy = []
760    for item in listx:
761        item = "0x" + item
762        listy.append(item)
763    return listy
764
765
766def modify_and_fetch_threshold(old_threshold, threshold_list):
767    r"""
768    Description of argument(s):
769
770        old_threshold              List of threshold values of sensor,
771        threshold_list             List of higher and lower of critical and non-critical values.
772                                   i,e [ "lcr", "lnc", "unc", "ucr" ]
773
774    Gets old threshold values from sensor and threshold levels,
775    then returns the list of new threshold and the dict of threshold levels
776
777    For example :
778    1. If old_threshold list is [ 1, 2, 3, 4] then the newthreshold_list will be [ 101, 102, 103, 104 ].
779       If old_threshold has 'na' the same will be appended to new list, eg: [ 101, 102, 103, 104, 'na'].
780
781    2. The newthreshold_list will be zipped to dictionary with threshold_list levels,
782       Example : threshold_dict = { 'lcr': 101, 'lnc': 102, 'unc': 103, 'ucr': 104 }
783
784    """
785
786    # Adding the difference of 100 as less than this value,
787    # may not have greater impact as the sensor considered is a fan sensor.
788    # The set threshold may round off for certain values below 100.
789    n = 100
790    newthreshold_list = []
791    for th in old_threshold:
792        th = th.strip()
793        if th == 'na':
794            newthreshold_list.append('na')
795        else:
796            x = int(float(th)) + n
797            newthreshold_list.append(x)
798            n = n + 100
799    threshold_dict = dict(zip(threshold_list, newthreshold_list))
800    return newthreshold_list, threshold_dict
801