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 fetch_sdr_count(sdr_data):
357    r"""
358    Get IPMI SDR list and return the SDR OEM count.
359
360    The data is obtained by issuing the IPMI "sdr elist -vvv" command.  An
361    example is shown below:
362
363    SDR record ID   : 0x00cb
364    SDR record ID   : 0x00cc
365    SDR record type : 0xc0
366    SDR record next : 0xffff
367    SDR record bytes: 11
368    Getting 11 bytes from SDR at offset 5
369
370    For the data shown above, the SDR record type with 0xc0 count will be returned.
371    """
372
373    data = sdr_data.split("\n")
374    sdr_list = []
375    for i, j in enumerate(data):
376        a = j.split(":")
377        if a[0].strip() == "SDR record type":
378            sdr_list.append(a[1].strip())
379    return sdr_list.count("0xc0")
380
381
382def get_aux_version(version_id):
383    r"""
384    Get IPMI Aux version info data and return it.
385
386    Description of argument(s):
387    version_id                      The data is obtained by from BMC
388                                    /etc/os-release
389                                    (e.g. "xxx-v2.1-438-g0030304-r3-gfea8585").
390
391    In the prior example, the 3rd field is "438" is the commit version and
392    the 5th field is "r3" and value "3" is the release version.
393
394    Aux version return from this function 4380003.
395    """
396
397    # Commit version.
398    count = re.findall("-(\\d{1,4})-", version_id)
399
400    # Release version.
401    release = re.findall("-r(\\d{1,4})", version_id)
402    if release:
403        aux_version = count[0] + "{0:0>4}".format(release[0])
404    else:
405        aux_version = count[0] + "0000"
406
407    return aux_version
408
409
410def get_fru_info():
411    r"""
412    Get fru info and return it as a list of dictionaries.
413
414    The data is obtained by issuing the IPMI "fru print -N 50" command.  An
415    example is shown below:
416
417    FRU Device Description : Builtin FRU Device (ID 0)
418     Device not present (Unspecified error)
419
420    FRU Device Description : cpu0 (ID 1)
421     Board Mfg Date        : Sun Dec 31 18:00:00 1995
422     Board Mfg             : <Manufacturer Name>
423     Board Product         : PROCESSOR MODULE
424     Board Serial          : YA1934315964
425     Board Part Number     : 02CY209
426
427    FRU Device Description : cpu1 (ID 2)
428     Board Mfg Date        : Sun Dec 31 18:00:00 1995
429     Board Mfg             : <Manufacturer Name>
430     Board Product         : PROCESSOR MODULE
431     Board Serial          : YA1934315965
432     Board Part Number     : 02CY209
433
434    For the data shown above, the following list of dictionaries will be
435    returned.
436
437    fru_obj:
438      fru_obj[0]:
439        [fru_device_description]:  Builtin FRU Device (ID 0)
440        [state]:                   Device not present (Unspecified error)
441      fru_obj[1]:
442        [fru_device_description]:  cpu0 (ID 1)
443        [board_mfg_date]:          Sun Dec 31 18:00:00 1995
444        [board_mfg]:               <Manufacturer Name>
445        [board_product]:           PROCESSOR MODULE
446        [board_serial]:            YA1934315964
447        [board_part_number]:       02CY209
448      fru_obj[2]:
449        [fru_device_description]:  cpu1 (ID 2)
450        [board_mfg_date]:          Sun Dec 31 18:00:00 1995
451        [board_mfg]:               <Manufacturer Name>
452        [board_product]:           PROCESSOR MODULE
453        [board_serial]:            YA1934315965
454        [board_part_number]:       02CY209
455    """
456
457    status, ret_values = grk.run_key_u(
458        "Run IPMI Standard Command  fru print -N 50"
459    )
460
461    # Manipulate the "Device not present" line to create a "state" key.
462    ret_values = re.sub(
463        "Device not present", "state : Device not present", ret_values
464    )
465
466    return [
467        vf.key_value_outbuf_to_dict(x) for x in re.split("\n\n", ret_values)
468    ]
469
470
471def get_component_fru_info(component="cpu", fru_objs=None):
472    r"""
473    Get fru info for the given component and return it as a list of
474    dictionaries.
475
476    This function calls upon get_fru_info and then filters out the unwanted
477    entries.  See get_fru_info's prolog for a layout of the data.
478
479    Description of argument(s):
480    component                       The component (e.g. "cpu", "dimm", etc.).
481    fru_objs                        A fru_objs list such as the one returned
482                                    by get_fru_info.  If this is None, then
483                                    this function will call get_fru_info to
484                                    obtain such a list.
485                                    Supplying this argument may improve
486                                    performance if this function is to be
487                                    called multiple times.
488    """
489
490    if fru_objs is None:
491        fru_objs = get_fru_info()
492    return [
493        x
494        for x in fru_objs
495        if re.match(component + "([0-9]+)? ", x["fru_device_description"])
496    ]
497
498
499def get_user_info(userid, channel_number=1):
500    r"""
501    Get user info using channel command and return it as a dictionary.
502
503    Description of argument(s):
504    userid          The userid (e.g. "1", "2", etc.).
505    channel_number  The user's channel number (e.g. "1").
506
507    Note: If userid is blank, this function will return a list of dictionaries.  Each list entry represents
508    one userid record.
509
510    The data is obtained by issuing the IPMI "channel getaccess" command.  An
511    example is shown below for user id 1 and channel number 1.
512
513    Maximum User IDs     : 15
514    Enabled User IDs     : 1
515    User ID              : 1
516    User Name            : root
517    Fixed Name           : No
518    Access Available     : callback
519    Link Authentication  : enabled
520    IPMI Messaging       : enabled
521    Privilege Level      : ADMINISTRATOR
522    Enable Status        : enabled
523
524    For the data shown above, the following dictionary will be returned.
525
526    user_info:
527      [maximum_userids]:     15
528      [enabled_userids:      1
529      [userid]               1
530      [user_name]            root
531      [fixed_name]           No
532      [access_available]     callback
533      [link_authentication]  enabled
534      [ipmi_messaging]       enabled
535      [privilege_level]      ADMINISTRATOR
536      [enable_status]        enabled
537    """
538
539    status, ret_values = grk.run_key_u(
540        "Run IPMI Standard Command  channel getaccess "
541        + str(channel_number)
542        + " "
543        + str(userid)
544    )
545
546    if userid == "":
547        return vf.key_value_outbuf_to_dicts(ret_values, process_indent=1)
548    else:
549        return vf.key_value_outbuf_to_dict(ret_values, process_indent=1)
550
551
552def channel_getciphers_ipmi():
553    r"""
554    Run 'channel getciphers ipmi' command and return the result as a list of dictionaries.
555
556    Example robot code:
557    ${ipmi_channel_ciphers}=  Channel Getciphers IPMI
558    Rprint Vars  ipmi_channel_ciphers
559
560    Example output:
561    ipmi_channel_ciphers:
562      [0]:
563        [id]:                                         3
564        [iana]:                                       N/A
565        [auth_alg]:                                   hmac_sha1
566        [integrity_alg]:                              hmac_sha1_96
567        [confidentiality_alg]:                        aes_cbc_128
568      [1]:
569        [id]:                                         17
570        [iana]:                                       N/A
571        [auth_alg]:                                   hmac_sha256
572        [integrity_alg]:                              sha256_128
573        [confidentiality_alg]:                        aes_cbc_128
574    """
575
576    cmd_buf = "channel getciphers ipmi | sed -re 's/ Alg/_Alg/g'"
577    stdout, stderr, rc = execute_ipmi_cmd(cmd_buf, "external", print_output=0)
578    return vf.outbuf_to_report(stdout)
579
580
581def get_device_id_config():
582    r"""
583    Get the device id config data and return as a dictionary.
584
585    Example:
586
587    dev_id_config =  get_device_id_config()
588    print_vars(dev_id_config)
589
590    dev_id_config:
591        [manuf_id]:            7244
592        [addn_dev_support]:     141
593        [prod_id]:            16976
594        [aux]:                    0
595        [id]:                    32
596        [revision]:             129
597        [device_revision]:        1
598    """
599    stdout, stderr, rc = bsu.bmc_execute_command(
600        "cat /usr/share/ipmi-providers/dev_id.json"
601    )
602
603    result = json.loads(stdout)
604
605    # Create device revision field for the user.
606    # Reference IPMI specification v2.0 "Get Device ID Command"
607    # [7]   1 = device provides Device SDRs
608    #       0 = device does not provide Device SDRs
609    # [6:4] reserved. Return as 0.
610    # [3:0] Device Revision, binary encoded.
611
612    result["device_revision"] = result["revision"] & 0x0F
613
614    return result
615
616
617def get_chassis_status():
618    r"""
619    Get IPMI chassis status data and return it as a dictionary.
620
621    The data is obtained by issuing the IPMI "chassis status" command. An
622    example is shown below:
623
624    System Power              : off
625    Power Overload            : false
626    Power Interlock           : inactive
627    Main Power Fault          : false
628    Power Control Fault       : false
629    Power Restore Policy      : previous
630    Last Power Event          :
631    Chassis Intrusion         : inactive
632    Front-Panel Lockout       : inactive
633    Drive Fault               : false
634    Cooling/Fan Fault         : false
635    Sleep Button Disable      : not allowed
636    Diag Button Disable       : not allowed
637    Reset Button Disable      : not allowed
638    Power Button Disable      : allowed
639    Sleep Button Disabled     : false
640    Diag Button Disabled      : false
641    Reset Button Disabled     : false
642    Power Button Disabled     : false
643
644    For the data shown above, the following dictionary will be returned.
645
646    chassis_status:
647      [system_power]:                        off
648      [power_overload]:                      false
649      [power_interlock]:                     inactive
650      [main_power_fault]:                    false
651      [power_control_fault]:                 false
652      [power_restore_policy]:                previous
653      [last_power_event]:
654      [chassis_intrusion]:                   inactive
655      [front-panel_lockout]:                 inactive
656      [drive_fault]:                         false
657      [cooling/fan_fault]:                   false
658      [sleep_button_disable]:                not allowed
659      [diag_button_disable]:                 not allowed
660      [reset_button_disable]:                not allowed
661      [power_button_disable]:                allowed
662      [sleep_button_disabled]:               false
663      [diag_button_disabled]:                false
664      [reset_button_disabled]:               false
665      [power_button_disabled]:               false
666    """
667
668    status, ret_values = grk.run_key_u(
669        "Run IPMI Standard Command  chassis status"
670    )
671    result = vf.key_value_outbuf_to_dict(ret_values, process_indent=1)
672
673    return result
674
675
676def get_channel_info(channel_number=1):
677    r"""
678    Get the channel info and return as a dictionary.
679    Example:
680
681    channel_info:
682      [channel_0x2_info]:
683        [channel_medium_type]:                        802.3 LAN
684        [channel_protocol_type]:                      IPMB-1.0
685        [session_support]:                            multi-session
686        [active_session_count]:                       0
687        [protocol_vendor_id]:                         7154
688      [volatile(active)_settings]:
689        [alerting]:                                   enabled
690        [per-message_auth]:                           enabled
691        [user_level_auth]:                            enabled
692        [access_mode]:                                always available
693      [non-volatile_settings]:
694        [alerting]:                                   enabled
695        [per-message_auth]:                           enabled
696        [user_level_auth]:                            enabled
697        [access_mode]:                                always available
698    """
699
700    status, ret_values = grk.run_key_u(
701        "Run IPMI Standard Command  channel info " + str(channel_number)
702    )
703    key_var_list = list(filter(None, ret_values.split("\n")))
704    # To match the dict format, add a colon after 'Volatile(active) Settings' and 'Non-Volatile Settings'
705    # respectively.
706    key_var_list[6] = "Volatile(active) Settings:"
707    key_var_list[11] = "Non-Volatile Settings:"
708    result = vf.key_value_list_to_dict(key_var_list, process_indent=1)
709    return result
710
711
712def get_user_access_ipmi(channel_number=1):
713    r"""
714    Run 'user list [<channel number>]' command and return the result as a list of dictionaries.
715
716    Example robot code:
717    ${users_access}=  user list 1
718    Rprint Vars  users_access
719
720    Example output:
721    users:
722      [0]:
723        [id]:                                         1
724        [name]:                                       root
725        [callin]:                                     false
726        [link]:                                       true
727        [auth]:                                       true
728        [ipmi]:                                       ADMINISTRATOR
729      [1]:
730        [id]:                                         2
731        [name]:                                       axzIDwnz
732        [callin]:                                     true
733        [link]:                                       false
734        [auth]:                                       true
735        [ipmi]:                                       ADMINISTRATOR
736    """
737
738    cmd_buf = "user list " + str(channel_number)
739    stdout, stderr, rc = execute_ipmi_cmd(cmd_buf, "external", print_output=0)
740    return vf.outbuf_to_report(stdout)
741
742
743def get_channel_auth_capabilities(channel_number=1, privilege_level=4):
744    r"""
745    Get the channel authentication capabilities and return as a dictionary.
746
747    Example:
748
749    channel_auth_cap:
750        [channel_number]:                               2
751        [ipmi_v1.5__auth_types]:
752        [kg_status]:                                    default (all zeroes)
753        [per_message_authentication]:                   enabled
754        [user_level_authentication]:                    enabled
755        [non-null_user_names_exist]:                    yes
756        [null_user_names_exist]:                        no
757        [anonymous_login_enabled]:                      no
758        [channel_supports_ipmi_v1.5]:                   no
759        [channel_supports_ipmi_v2.0]:                   yes
760    """
761
762    status, ret_values = grk.run_key_u(
763        "Run IPMI Standard Command  channel authcap "
764        + str(channel_number)
765        + " "
766        + str(privilege_level)
767    )
768    result = vf.key_value_outbuf_to_dict(ret_values, process_indent=1)
769
770    return result
771
772
773def fetch_date(date):
774    r"""
775    Removes prefix 0 in a date in given date
776
777    Example : 08/12/2021 then returns 8/12/2021
778    """
779
780    date = date.lstrip("0")
781    return date
782
783
784def fetch_added_sel_date(entry):
785    r"""
786    Split sel entry string with with | and join only the date with space
787
788    Example : If entry given is, "a | 02/14/2020 | 01:16:58 | Sensor_type #0x17 |  | Asserted"
789    Then the result will be "02/14/2020 01:16:58"
790    """
791
792    temp = entry.split(" | ")
793    date = temp[1] + " " + temp[2]
794    print(date)
795    return date
796
797
798def prefix_bytes(listx):
799    r"""
800    prefixes byte strings in list
801
802    Example:
803    ${listx} = ['01', '02', '03']
804    ${listx}=  Prefix Bytes  ${listx}
805    then,
806    ${listx}= ['0x01', '0x02', '0x03']
807
808    """
809
810    listy = []
811    for item in listx:
812        item = "0x" + item
813        listy.append(item)
814    return listy
815
816
817def modify_and_fetch_threshold(old_threshold, threshold_list):
818    r"""
819    Description of argument(s):
820
821        old_threshold              List of threshold values of sensor,
822        threshold_list             List of higher and lower of critical and non-critical values.
823                                   i,e [ "lcr", "lnc", "unc", "ucr" ]
824
825    Gets old threshold values from sensor and threshold levels,
826    then returns the list of new threshold and the dict of threshold levels
827
828    For example :
829    1. If old_threshold list is [ 1, 2, 3, 4] then the newthreshold_list will be [ 101, 102, 103, 104 ].
830       If old_threshold has 'na' the same will be appended to new list, eg: [ 101, 102, 103, 104, 'na'].
831
832    2. The newthreshold_list will be zipped to dictionary with threshold_list levels,
833       Example : threshold_dict = { 'lcr': 101, 'lnc': 102, 'unc': 103, 'ucr': 104 }
834
835    """
836
837    # Adding the difference of 100 as less than this value,
838    # may not have greater impact as the sensor considered is a fan sensor.
839    # The set threshold may round off for certain values below 100.
840    n = 100
841    newthreshold_list = []
842    for th in old_threshold:
843        th = th.strip()
844        if th == "na":
845            newthreshold_list.append("na")
846        else:
847            x = int(float(th)) + n
848            newthreshold_list.append(x)
849            n = n + 100
850    threshold_dict = dict(zip(threshold_list, newthreshold_list))
851    return newthreshold_list, threshold_dict
852