diff options
Diffstat (limited to 'pyipmi/commands/sel.py')
-rw-r--r-- | pyipmi/commands/sel.py | 229 |
1 files changed, 229 insertions, 0 deletions
diff --git a/pyipmi/commands/sel.py b/pyipmi/commands/sel.py new file mode 100644 index 0000000..847468d --- /dev/null +++ b/pyipmi/commands/sel.py @@ -0,0 +1,229 @@ +# 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. + + +"""This module contains a series of wrappers + around SEL commands for ipmitool +""" + +import os +import re +import tempfile +import string +from pyipmi import Command, IpmiError +from pyipmi.tools.responseparser import ResponseParserMixIn, str2bool +from pyipmi.sel import (SELTimestamp, SELInfo, SELAllocInfo, SELRecord, + SELOverflowError, SELTimestampError) + + +class SELTimeSetCommand(Command, ResponseParserMixIn): + """Describes the Set SEL Time command""" + + name = "Set SEL Time" + # TODO: get response data from ipmitool + + @property + def ipmitool_args(self): + """return args for ipmitool command""" + return ["sel", "time", "set", self._params["time"].timestamp] + + def handle_command_error(self, resp, err): + raise SELTimestampError(err) + + +class SELTimeGetCommand(Command, ResponseParserMixIn): + """Describes the Get SEL Time command""" + + def response_parser(self, resp, err): + """A helper function to parse a timestamp returned from + an 'sel time get' command + """ + + return SELTimestamp(resp.strip()) + + name = "Get SEL Time" + result_type = SELTimestamp + ipmitool_args = ["sel", "time", "get"] + + +class SELInfoCommand(Command, ResponseParserMixIn): + """Describes the Get SEL Info command""" + + def version_parser(string): + vdict = {} + vregex = '(?P<number>[12]\.[05]) \((?P<compliant>.+) compliant\)' + match = re.match(vregex, string) + vdict['number'] = match.group('number') + vdict['compliant'] = match.group('compliant').split(', ') + return vdict + + name = "SEL Info" + ipmitool_args = ["sel", "info"] + result_type = SELInfo + + response_fields = { + 'Version' : {'parser': version_parser}, + 'Entries' : {'parser': lambda s: int(s)}, + 'Free Space' : {'parser': lambda s: int(s[:-6])}, #removes ' bytes' + 'Last Add Time' : {'parser': lambda ts: SELTimestamp(ts)}, + 'Last Del Time' : {'parser': lambda ts: SELTimestamp(ts)}, + 'Overflow' : {'parser': str2bool}, + 'Supported Cmds' : {'parser': lambda s: re.findall("\w[ \w]+", s)} + } + + +class SELAllocInfoCommand(Command, ResponseParserMixIn): + """Describes the sel alloc info command""" + + name = "SEL Alloc Info" + ipmitool_args = ["sel", "info"] + result_type = SELAllocInfo + + response_fields = { + '# of Alloc Units' : {'attr': 'num_alloc_units', 'parser': lambda s: int(s)}, + 'Alloc Unit Size' : {'parser': lambda s: int(s)}, + '# Free Units' : {'attr': 'num_free_units', 'parser': lambda s: int(s)}, + 'Largest Free Blk' : {'parser': lambda s: int(s)}, + 'Max Record Size' : {'parser': lambda s: int(s)} + } + + +class SELAddCommand(Command, ResponseParserMixIn): + """Describes the sel add command""" + + #TODO: get response data from ipmitool + + name = "SEL Add" + + def __init__(self, *args, **kwargs): + super(SELAddCommand, self).__init__(*args, **kwargs) + self._tmpfile = tempfile.NamedTemporaryFile(delete=False) + + for e in self._params['records']: + # TODO: handle other types of SEL Records + # TODO: allow for malformed SEL entries + entry = ('%s %s %s %s %s %s %s' % + (hex(e.evm_rev), hex(e.sensor_type), hex(e.sensor_number), + hex((e.event_direction << 7) | e.event_type), + hex(e.event_data[0]), hex(e.event_data[1]), hex(e.event_data[2]))) + self._tmpfile.write(str(entry) + '\n') + self._tmpfile.flush() + + def __del__(self): + os.remove(self._tmpfile.name) + + @property + def ipmitool_args(self): + """return args for ipmitool command""" + return ["sel", "add", self._tmpfile.name] + + def handle_command_error(self, resp, err): + if err.find('Out of space') > 0: + raise SELOverflowError(err) + + raise IpmiError(err) + + +class SELGetCommand(Command, ResponseParserMixIn): + """Describes the sel get command""" + + def event_data_parser(string): + data = int(string, 16) + return (data >> 16, (data >> 8) & 0xff, data & 0xff) + + def response_parser(self, response, err): + if err.find("command failed") > 0: + return None + + entry = self.parse_colon_record(response, err) + entry.normalize() + return entry + + + direction_parser = lambda d: 0 if d == 'Assertion Event' else 1 + hex_parser = lambda x: int(x, 16) + + name = "SEL Get" + result_type = SELRecord + + @property + def ipmitool_args(self): + """return args for ipmitool command""" + return ["sel", "get"] + list(self._params['record_ids']) + + # TODO: add support for oem records + response_fields = { + 'SEL Record ID': {'parser': hex_parser, 'attr': 'record_id'}, + 'Record Type' : {'parser': hex_parser}, + 'Timestamp': {}, + 'Generator ID': {'parser': hex_parser}, + 'EvM Revision': {'parser': hex_parser}, + 'Sensor Type': {}, #TODO: covert to hex code + 'Sensor Number': {'parser': hex_parser}, + 'Event Type': {}, #TODO: convert to hex code + 'Event Direction': {'parser': direction_parser}, + 'Event Data': {'parser': event_data_parser}, + 'Description': {} + } + + +class SELClearCommand(Command, ResponseParserMixIn): + """Describes the Clear SEL command""" + + name = "Clear SEL" + ipmitool_args = ["sel", "clear"] + # TODO: get response data from ipmitool + + +class SELListCommand(Command, ResponseParserMixIn): + """Describes SEL List command + note: this command is non-standard + """ + + def response_parser(self, resp, err): + sel_list = resp.strip().split('\n') + sel_list = map(string.strip, sel_list) + return filter(lambda s: s != '', sel_list) # remove blank entries + + name = "List SEL" + ipmitool_args = ["sel", "list"] + result_type = list + + +sel_commands = { + "set_sel_time" : SELTimeSetCommand, + "get_sel_time" : SELTimeGetCommand, + "sel_info" : SELInfoCommand, + "sel_alloc_info" : SELAllocInfoCommand, + "sel_add" : SELAddCommand, + "sel_get" : SELGetCommand, + "sel_clear" : SELClearCommand, + "sel_list" : SELListCommand +} |