summaryrefslogtreecommitdiff
path: root/pyipmi/__init__.py
diff options
context:
space:
mode:
Diffstat (limited to 'pyipmi/__init__.py')
-rw-r--r--pyipmi/__init__.py213
1 files changed, 213 insertions, 0 deletions
diff --git a/pyipmi/__init__.py b/pyipmi/__init__.py
new file mode 100644
index 0000000..ef6c175
--- /dev/null
+++ b/pyipmi/__init__.py
@@ -0,0 +1,213 @@
+# Copyright (c) 2012, Calxeda Inc.
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of Calxeda Inc. nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+# DAMAGE.
+
+
+"""pyipmi provides IPMI client functionality"""
+from __future__ import print_function
+
+__all__ = ['Handle', 'Tool', 'Command', 'make_bmc', 'IpmiError']
+
+class Handle:
+ """A handle to speak with a BMC
+
+ Handles use a Tool to speak with a BMC. It's basically a session handle
+ from its user's perspective, although handles may or may not use a single
+ ipmi session for their duration, depending on their implementation.
+
+ The Handle class itself is concrete, but may become abstract in the future.
+ """
+
+ def __init__(self, bmc, tool_class, command_list):
+ """
+ Arguments:
+ bmc -- A BMC object
+ tool_class -- the class of the tool to be used for this handle,
+ for example, IpmiTool.
+ command_list -- a list of Commands to be made available to this handle.
+ """
+ self.bmc = bmc
+ self._tool = tool_class(self, command_list)
+ self._add_command_stubs(command_list)
+ self._log_file = None
+
+ def _add_command_stubs(self, command_list):
+ """Adds command methods to an instance of Handle
+
+ Each command in the command_list supplied to init will add a method to
+ this handle instance. Calling that method causes the command to be issued.
+ """
+ for command in command_list:
+ self._add_command_stub(command)
+
+ def _add_command_stub(self, command):
+ """Add a a method for a command"""
+ def _cmd(*args, **kwargs):
+ """Call the method of the same name on the tool"""
+ tool_method = getattr(self._tool, command)
+ return tool_method(*args, **kwargs)
+
+ setattr(self, command, _cmd)
+
+ def set_log(self, log_file):
+ """Setup a logger for the handle
+
+ Arguments:
+ log_file -- a file like object
+ """
+ self._log_file = log_file
+
+ def set_verbose(self, verbose):
+ """Set verbosity for the handle
+
+ Arguments:
+ verbose -- true or false
+ """
+ self._verbose = verbose
+
+ def log(self, string):
+ """Write a string to a log
+
+ The log is flushed after log is written
+
+ Arguments:
+ string -- the string to log."""
+ if len(string) > 0:
+ if (self._log_file):
+ print(string, file = self._log_file)
+ self._log_file.flush()
+ if (self._verbose):
+ print(string)
+
+class Tool(object):
+ """A tool implements communications with a BMC
+
+ Tool is an abstract class - it needs a 'run' method defined to be useful.
+
+ Tool implementations vary in the way they implement IPMI communications.
+ The IpmiTool implementation uses high level ipmitool commands executed via
+ subprocesses. A freeipmi implementation could do the same using freeipmi
+ commands, or there could be a RawIpmiTool implementation that used IpmiTool
+ with raw commands. Another possibility is implementing IPMI natively in
+ python, and having a NativeIpmi Tool implementation for that.
+
+ Tool instances are bound to handle instances - each tool has exactly one
+ handle.
+
+ Tool instances are created with a list of commands - each command in the
+ list causes a method (named after the command) to be added to the tool
+ for executing the command. Commands in the list must implement support
+ for the tool - each tool has
+
+ Concrete implementations should go in the tools directory. An example
+ concrete implementation is the ImpiTool class.
+ """
+ def __init__(self, handle, command_list):
+ """
+ Arguments:
+ handle -- the handle to which this command is bound
+ command_list -- the list of commands the tool can execute
+ """
+ self._handle = handle
+ self._add_command_stubs(command_list)
+ self._command_list = command_list
+
+ def _add_command_stubs(self, command_list):
+ """Add command methods to this Tool instance
+
+ Just like handles, tools get a method per command in command_list
+ """
+ for command in command_list:
+ self._add_command_stub(command)
+
+ def _add_command_stub(self, command):
+ """Add an individual command method"""
+ def _cmd(*args, **kwargs):
+ """An individual command method.
+
+ Uses this tool's run method to execute a command in this
+ tool's special way."""
+ inst = self._command_list[command](self, *args, **kwargs)
+ return self.run(inst)
+
+ setattr(self, command, _cmd)
+
+ def _log(self, string):
+ """Log a message via this tool's handle"""
+ self._handle.log(string)
+
+ def run(self, command):
+ """This should be defined in a subclass of Tool"""
+ pass
+
+class Command:
+ """A Command describes a specific IPMI command"""
+ def __init__(self, tool, **params):
+ self._tool = tool
+ self._params = params
+
+class InteractiveCommand(Command):
+ """A dummy class for an interactive command"""
+
+def make_bmc(bmc_class, logfile = None, verbose = True, **kwargs):
+ """Returns a bmc object with 'default' settings
+
+ This uses IpmiTool for the tool,the base Handle class, and
+ the default "ipmi_commands" list of IPMI commands.
+
+ kwargs is combined with those default settings into a single
+ dict with its contents passed as keyword args when calling
+ bmc_class.
+
+ Arguments:
+ bmc_class -- called w/ kwargs as its parameter to get the
+ object to return.
+
+ Keyword arguments:
+ logfile -- an optional file object for logging (default none)
+ """
+
+ from commands import ipmi_commands
+ from tools import IpmiTool
+ bmc_kwargs = {
+ 'tool_class' : IpmiTool,
+ 'handle_class' : Handle,
+ 'command_list' : ipmi_commands
+ }
+
+ bmc_kwargs.update(kwargs)
+ bmc_obj = bmc_class(**bmc_kwargs)
+ bmc_obj.handle.set_log(logfile)
+ bmc_obj.handle.set_verbose(verbose)
+
+ return bmc_obj
+
+
+class IpmiError(Exception):
+ """A wrapper for an Ipmi error"""