Re-structured lib/ipmi_client.py

create_ipmi_ext_command_string:
 - Create and return an IPMI external command string which is fit to be run
   from a bash command line.
verify_ipmi_user_parm_accepted:
- Deterimine whether the OBMC accepts the -U ipmitool argument and adjust
  the global ipmi_required_args accordingly.
ipmi_setup:
 - Perform all required setup for running iptmitool commands.

Change-Id: I85cccfbd7ff237e5a87e8dd4e16579603635e5a8
Signed-off-by: Michael Walsh <micwalsh@us.ibm.com>
diff --git a/lib/ipmi_client.py b/lib/ipmi_client.py
index f3394d7..2327f75 100644
--- a/lib/ipmi_client.py
+++ b/lib/ipmi_client.py
@@ -4,85 +4,148 @@
 A python companion file for ipmi_client.robot.
 """
 
+import collections
 import gen_print as gp
 import gen_cmd as gc
 from robot.libraries.BuiltIn import BuiltIn
 
 
-def build_ipmi_ext_cmd(ipmi_cipher_level=None, quiet=None):
+# Set default values for required IPMI options.
+ipmi_interface = 'lanplus'
+ipmi_cipher_suite = BuiltIn().get_variable_value("${IPMI_CIPHER_LEVEL}", '3')
+ipmi_username = BuiltIn().get_variable_value("${IPMI_USERNAME}", "root")
+ipmi_password = BuiltIn().get_variable_value("${IPMI_PASSWORD}", "0penBmc")
+ipmi_host = BuiltIn().get_variable_value("${OPENBMC_HOST}")
+
+# Create a list of the required IPMI options.
+ipmi_required_options = ['I', 'C', 'U', 'P', 'H']
+# The following dictionary maps the ipmitool option names (e.g. "I") to our
+# more descriptive names (e.g. "interface") for the required options.
+ipmi_option_name_map = {
+    'I': 'interface',
+    'C': 'cipher_suite',
+    'U': 'username',
+    'P': 'password',
+    'H': 'host',
+}
+
+
+def create_ipmi_ext_command_string(command, **options):
     r"""
-    Build the global IPMI_EXT_CMD variable.
+    Create and return an IPMI external command string which is fit to be run
+    from a bash command line.
 
-    If global variable IPMI_EXT_CMD already has a value, this keyword will
-    simply return without taking any action with the following exception:
+    Example:
 
-    If ipmi_cipher_level is is anything but None, this function will continue
-    on and re-build the IPMI_EXT_CMD variable.
+    ipmi_ext_cmd = create_ipmi_ext_command_string('power status')
 
-    This keyword is designed for use by keywords which use the IPMI_EXT_CMD
-    variable (e.g. 'Run External IPMI Raw Command').  This keyword is
-    warranted because the ipmitool program may or may not accept the -U (i.e.
-    username) parameter depending on the version of code loaded on the BMC.
-    This keyword will determine whether the "-U" parameter should be used and
-    create IPMI_EXT_CMD accordingly.
+    Result:
+    ipmitool -I lanplus -C 3 -P ******** -H x.x.x.x power status
 
-    Furthermore, this keyword will run the command to create the 'root' IPMI
-    username.
+    Example:
+
+    ipmi_ext_cmd = create_ipmi_ext_command_string('power status', C='4')
+
+    Result:
+    ipmitool -I lanplus -C 4 -P ******** -H x.x.x.x power status
 
     Description of argument(s):
-    # ipmi_cipher_level             IPMI cipher level value
-    #                               (e.g. "1", "2", "3", "15", "16", "17").
-    # quiet                         Indicates whether this keyword should run
-    #                               without any output to the console.
+    command                         The ipmitool command (e.g. 'power status').
+    options                         Any desired options that are understood by
+                                    ipmitool (see iptmitool's help text for a
+                                    complete list).  If the caller does NOT
+                                    provide any of several required options
+                                    (e.g. "P", i.e. password), this function
+                                    will include them on the caller's behalf
+                                    using default values.
     """
 
-    ipmi_ext_cmd = BuiltIn().get_variable_value("${IPMI_EXT_CMD}", "")
-    if ipmi_ext_cmd != "" and not ipmi_cipher_level:
-        return
+    new_options = collections.OrderedDict()
+    for option in ipmi_required_options:
+        if option in options:
+            # If the caller has specified this particular option, use it in
+            # preference to the default value.
+            new_options[option] = options[option]
+            # Delete the value from the caller's options.
+            del options[option]
+        else:
+            # The caller hasn't specified this required option so specify it
+            # for them using the global value.
+            var_name = 'ipmi_' + ipmi_option_name_map[option]
+            value = eval(var_name)
+            new_options[option] = value
+    # Include the remainder of the caller's options in the new options
+    # dictionary.
+    for key, value in options.items():
+        new_options[key] = value
 
-    quiet = int(gp.get_var_value(quiet, 0))
-    openbmc_host = BuiltIn().get_variable_value("${OPENBMC_HOST}")
-    ipmi_username = BuiltIn().get_variable_value("${IPMI_USERNAME}", "root")
-    ipmi_password = BuiltIn().get_variable_value("${IPMI_PASSWORD}",
-                                                 "0penBmc")
-    if not ipmi_cipher_level:
-        ipmi_cipher_level = BuiltIn().get_variable_value("${IPMI_CIPHER_LEVEL}",
-                                                         "3")
+    return gc.create_command_string('ipmitool', command, new_options)
 
-    old_ipmi_ext_cmd = "ipmitool -I lanplus -C " + str(ipmi_cipher_level)\
-        + " -P " + ipmi_password
-    new_ipmi_ext_cmd = "ipmitool -I lanplus -C " + str(ipmi_cipher_level)\
-        + " -U " + ipmi_username + " -P " + ipmi_password
-    # Use a basic ipmitool command to help us determine whether the BMC will
-    # accept the -U parm.
-    ipmi_cmd = "power status"
-    ipmi_cmd_suffix = " -H " + openbmc_host + " " + ipmi_cmd
+
+def verify_ipmi_user_parm_accepted():
+    r"""
+    Deterimine whether the OBMC accepts the '-U' ipmitool option and adjust
+    the global ipmi_required_options accordingly.
+    """
+
+    # Assumption: "U" is in the global ipmi_required_options.
+    global ipmi_required_options
     print_output = 0
-    cmd_buf = new_ipmi_ext_cmd + ipmi_cmd_suffix
-    new_rc, stdout = gc.shell_cmd(cmd_buf,
-                                  print_output=print_output,
-                                  show_err=0,
-                                  ignore_err=1)
-    gp.qprint_varx("rc", new_rc, 1)
-    if new_rc == 0:
-        ipmi_ext_cmd = new_ipmi_ext_cmd
-        BuiltIn().set_global_variable("${IPMI_EXT_CMD}", ipmi_ext_cmd)
+
+    command_string = create_ipmi_ext_command_string('power status')
+    rc, stdout = gc.shell_cmd(command_string,
+                              print_output=print_output,
+                              show_err=0,
+                              ignore_err=1)
+    gp.qprint_var(rc, 1)
+    if rc == 0:
+        # The OBMC accepts the ipmitool "-U" option so new further work needs
+        # to be done.
         return
 
-    cmd_buf = old_ipmi_ext_cmd + ipmi_cmd_suffix
-    old_rc, stdout = gc.shell_cmd(cmd_buf,
-                                  print_output=print_output,
-                                  show_err=0,
-                                  ignore_err=1)
-    gp.qprint_varx("rc", old_rc, 1)
-
-    if old_rc == 0:
-        ipmi_ext_cmd = old_ipmi_ext_cmd
-        BuiltIn().set_global_variable("${IPMI_EXT_CMD}", ipmi_ext_cmd)
+    # Remove the "U" option from ipmi_required_options to allow us to create a
+    # command string without the "U" option.
+    if 'U' in ipmi_required_options:
+        del ipmi_required_options[ipmi_required_options.index('U')]
+    command_string = create_ipmi_ext_command_string('power status')
+    rc, stdout = gc.shell_cmd(command_string,
+                              print_output=print_output,
+                              show_err=0,
+                              ignore_err=1)
+    gp.qprint_var(rc, 1)
+    if rc == 0:
+        # The "U" option has been removed from the ipmi_required_options
+        # global variable.
         return
 
-    message = "Unable to run ipmitool, (with or without the '-U' parm)."
-    BuiltIn().fail(message)
+    message = "Unable to run ipmitool (with or without the '-U' option).\n"
+    gp.print_error(message)
+
+    # Revert to original ipmi_required_options by inserting 'U' right before
+    # 'P'.
+    ipmi_required_options.insert(ipmi_required_options.index('P'), 'U')
 
 
-build_ipmi_ext_cmd()
+def ipmi_setup():
+    r"""
+    Perform all required setup for running iptmitool commands.
+    """
+
+    verify_ipmi_user_parm_accepted()
+
+
+ipmi_setup()
+
+
+def process_ipmi_user_options(command):
+    r"""
+    Return the buffer with any ipmi_user_options pre-pended.
+
+    Description of argument(s):
+    command                         An IPMI command (e.g. "power status").
+    """
+
+    ipmi_user_options = BuiltIn().get_variable_value("${IPMI_USER_OPTIONS}", '')
+    if ipmi_user_options == "":
+        return command
+    return ipmi_user_options + " " + command