xref: /openbmc/openbmc-test-automation/lib/ipmi_client.py (revision 1f8db9c27614e117b4ed5ac5d0ca5160b68e8db7)
1#!/usr/bin/env python3
2
3r"""
4A python companion file for ipmi_client.robot.
5"""
6
7import collections
8
9import gen_cmd as gc
10import gen_print as gp
11from robot.libraries.BuiltIn import BuiltIn
12
13# Set default values for required IPMI options.
14ipmi_interface = "lanplus"
15ipmi_cipher_suite = BuiltIn().get_variable_value("${IPMI_CIPHER_LEVEL}", "17")
16ipmi_timeout = BuiltIn().get_variable_value("${IPMI_TIMEOUT}", "3")
17ipmi_port = BuiltIn().get_variable_value("${IPMI_PORT}", "623")
18ipmi_username = BuiltIn().get_variable_value("${IPMI_USERNAME}", "root")
19ipmi_password = BuiltIn().get_variable_value("${IPMI_PASSWORD}", "0penBmc")
20ipmi_host = BuiltIn().get_variable_value("${OPENBMC_HOST}")
21
22# Create a list of the required IPMI options.
23ipmi_required_options = ["I", "C", "N", "p", "U", "P", "H"]
24# The following dictionary maps the ipmitool option names (e.g. "I") to our
25# more descriptive names (e.g. "interface") for the required options.
26ipmi_option_name_map = {
27    "I": "interface",
28    "C": "cipher_suite",
29    "N": "timeout",
30    "p": "port",
31    "U": "username",
32    "P": "password",
33    "H": "host",
34}
35
36
37def create_ipmi_ext_command_string(command, **options):
38    r"""
39    Create and return an IPMI external command string which is fit to be run
40    from a bash command line.
41
42    Example:
43
44    ipmi_ext_cmd = create_ipmi_ext_command_string('power status')
45
46    Result:
47    ipmitool -I lanplus -C 3 -p 623 -P ******** -H x.x.x.x power status
48
49    Example:
50
51    ipmi_ext_cmd = create_ipmi_ext_command_string('power status', C='4')
52
53    Result:
54    ipmitool -I lanplus -C 4 -p 623 -P ******** -H x.x.x.x power status
55
56    Description of argument(s):
57    command                         The ipmitool command (e.g. 'power status').
58    options                         Any desired options that are understood by
59                                    ipmitool (see iptmitool's help text for a
60                                    complete list).  If the caller does NOT
61                                    provide any of several required options
62                                    (e.g. "P", i.e. password), this function
63                                    will include them on the caller's behalf
64                                    using default values.
65    """
66
67    new_options = collections.OrderedDict()
68    for option in ipmi_required_options:
69        # This is to prevent boot table "-N 10" vs user input timeout.
70        if " -N " in command and option == "N":
71            continue
72        if option in options:
73            # If the caller has specified this particular option, use it in
74            # preference to the default value.
75            new_options[option] = options[option]
76            # Delete the value from the caller's options.
77            del options[option]
78        else:
79            # The caller hasn't specified this required option so specify it
80            # for them using the global value.
81            var_name = "ipmi_" + ipmi_option_name_map[option]
82            value = eval(var_name)
83            new_options[option] = value
84    # Include the remainder of the caller's options in the new options
85    # dictionary.
86    for key, value in options.items():
87        new_options[key] = value
88
89    return gc.create_command_string("ipmitool", command, new_options)
90
91
92def verify_ipmi_user_parm_accepted():
93    r"""
94    Determine whether the OBMC accepts the '-U' ipmitool option and adjust
95    the global ipmi_required_options accordingly.
96    """
97
98    # Assumption: "U" is in the global ipmi_required_options.
99    print_output = 0
100
101    command_string = create_ipmi_ext_command_string("power status")
102    rc, stdout = gc.shell_cmd(
103        command_string, print_output=print_output, show_err=0, ignore_err=1
104    )
105    gp.qprint_var(rc, 1)
106    if rc == 0:
107        # The OBMC accepts the ipmitool "-U" option so new further work needs
108        # to be done.
109        return
110
111    # Remove the "U" option from ipmi_required_options to allow us to create a
112    # command string without the "U" option.
113    if "U" in ipmi_required_options:
114        del ipmi_required_options[ipmi_required_options.index("U")]
115    command_string = create_ipmi_ext_command_string("power status")
116    rc, stdout = gc.shell_cmd(
117        command_string, print_output=print_output, show_err=0, ignore_err=1
118    )
119    gp.qprint_var(rc, 1)
120    if rc == 0:
121        # The "U" option has been removed from the ipmi_required_options
122        # global variable.
123        return
124
125    message = "Unable to run ipmitool (with or without the '-U' option).\n"
126    gp.print_error(message)
127
128    # Revert to original ipmi_required_options by inserting 'U' right before
129    # 'P'.
130    ipmi_required_options.insert(ipmi_required_options.index("P"), "U")
131
132
133def ipmi_setup():
134    r"""
135    Perform all required setup for running iptmitool commands.
136    """
137
138    verify_ipmi_user_parm_accepted()
139
140
141ipmi_setup()
142
143
144def process_ipmi_user_options(command):
145    r"""
146    Return the buffer with any ipmi_user_options prepended.
147
148    Description of argument(s):
149    command                         An IPMI command (e.g. "power status").
150    """
151
152    ipmi_user_options = BuiltIn().get_variable_value(
153        "${IPMI_USER_OPTIONS}", ""
154    )
155    if ipmi_user_options == "":
156        return command
157    return ipmi_user_options + " " + command
158