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