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