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