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    global ipmi_required_options
100    print_output = 0
101
102    command_string = create_ipmi_ext_command_string("power status")
103    rc, stdout = gc.shell_cmd(
104        command_string, print_output=print_output, show_err=0, ignore_err=1
105    )
106    gp.qprint_var(rc, 1)
107    if rc == 0:
108        # The OBMC accepts the ipmitool "-U" option so new further work needs
109        # to be done.
110        return
111
112    # Remove the "U" option from ipmi_required_options to allow us to create a
113    # command string without the "U" option.
114    if "U" in ipmi_required_options:
115        del ipmi_required_options[ipmi_required_options.index("U")]
116    command_string = create_ipmi_ext_command_string("power status")
117    rc, stdout = gc.shell_cmd(
118        command_string, print_output=print_output, show_err=0, ignore_err=1
119    )
120    gp.qprint_var(rc, 1)
121    if rc == 0:
122        # The "U" option has been removed from the ipmi_required_options
123        # global variable.
124        return
125
126    message = "Unable to run ipmitool (with or without the '-U' option).\n"
127    gp.print_error(message)
128
129    # Revert to original ipmi_required_options by inserting 'U' right before
130    # 'P'.
131    ipmi_required_options.insert(ipmi_required_options.index("P"), "U")
132
133
134def ipmi_setup():
135    r"""
136    Perform all required setup for running iptmitool commands.
137    """
138
139    verify_ipmi_user_parm_accepted()
140
141
142ipmi_setup()
143
144
145def process_ipmi_user_options(command):
146    r"""
147    Return the buffer with any ipmi_user_options prepended.
148
149    Description of argument(s):
150    command                         An IPMI command (e.g. "power status").
151    """
152
153    ipmi_user_options = BuiltIn().get_variable_value(
154        "${IPMI_USER_OPTIONS}", ""
155    )
156    if ipmi_user_options == "":
157        return command
158    return ipmi_user_options + " " + command
159