xref: /openbmc/openbmc-test-automation/lib/ipmi_client.py (revision 02d32765119c4d5ce3af989fa3474754b7bbc2f3)
1 #!/usr/bin/env python3
2 
3 r"""
4 A python companion file for ipmi_client.robot.
5 """
6 
7 import collections
8 
9 import gen_cmd as gc
10 import gen_print as gp
11 from robot.libraries.BuiltIn import BuiltIn
12 
13 # Set default values for required IPMI options.
14 ipmi_interface = "lanplus"
15 ipmi_cipher_suite = BuiltIn().get_variable_value("${IPMI_CIPHER_LEVEL}", "17")
16 ipmi_timeout = BuiltIn().get_variable_value("${IPMI_TIMEOUT}", "3")
17 ipmi_port = BuiltIn().get_variable_value("${IPMI_PORT}", "623")
18 ipmi_username = BuiltIn().get_variable_value("${IPMI_USERNAME}", "root")
19 ipmi_password = BuiltIn().get_variable_value("${IPMI_PASSWORD}", "0penBmc")
20 ipmi_host = BuiltIn().get_variable_value("${OPENBMC_HOST}")
21 
22 # Create a list of the required IPMI options.
23 ipmi_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.
26 ipmi_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 
37 def 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 
92 def 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 
134 def ipmi_setup():
135     r"""
136     Perform all required setup for running iptmitool commands.
137     """
138 
139     verify_ipmi_user_parm_accepted()
140 
141 
142 ipmi_setup()
143 
144 
145 def 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