diff options
author | Lorry Tar Creator <lorry-tar-importer@baserock.org> | 2013-05-09 15:12:28 +0000 |
---|---|---|
committer | <> | 2013-06-05 17:10:08 +0000 |
commit | 2e54d50d349aafdc189eba2702e5913835cdf88f (patch) | |
tree | e69b4ab5d908d8792b884ba362c5c52cc94ab06f /pyipmi/commands | |
download | pyipmi-tarball-2e54d50d349aafdc189eba2702e5913835cdf88f.tar.gz |
Imported from /home/lorry/working-area/delta_pyipmi-tarball/pyipmi-0.7.1.tar.gz.HEADpyipmi-0.7.1masterbaserock/morph
Diffstat (limited to 'pyipmi/commands')
-rw-r--r-- | pyipmi/commands/__init__.py | 89 | ||||
-rw-r--r-- | pyipmi/commands/bmc.py | 152 | ||||
-rw-r--r-- | pyipmi/commands/bootdev.py | 80 | ||||
-rw-r--r-- | pyipmi/commands/bootparam.py | 66 | ||||
-rw-r--r-- | pyipmi/commands/channel.py | 201 | ||||
-rw-r--r-- | pyipmi/commands/chassis.py | 80 | ||||
-rw-r--r-- | pyipmi/commands/data.py | 125 | ||||
-rw-r--r-- | pyipmi/commands/dcmi.py | 337 | ||||
-rw-r--r-- | pyipmi/commands/event.py | 79 | ||||
-rw-r--r-- | pyipmi/commands/fabric.py | 306 | ||||
-rw-r--r-- | pyipmi/commands/fabric_config.py | 288 | ||||
-rw-r--r-- | pyipmi/commands/freeipmi_pef.py | 211 | ||||
-rw-r--r-- | pyipmi/commands/fru.py | 132 | ||||
-rw-r--r-- | pyipmi/commands/fw.py | 400 | ||||
-rw-r--r-- | pyipmi/commands/info.py | 92 | ||||
-rw-r--r-- | pyipmi/commands/lan.py | 127 | ||||
-rw-r--r-- | pyipmi/commands/mc.py | 69 | ||||
-rw-r--r-- | pyipmi/commands/payload.py | 65 | ||||
-rw-r--r-- | pyipmi/commands/pef.py | 130 | ||||
-rw-r--r-- | pyipmi/commands/pet.py | 55 | ||||
-rw-r--r-- | pyipmi/commands/sdr.py | 110 | ||||
-rw-r--r-- | pyipmi/commands/sel.py | 229 | ||||
-rw-r--r-- | pyipmi/commands/sol.py | 207 | ||||
-rw-r--r-- | pyipmi/commands/user.py | 163 | ||||
-rw-r--r-- | pyipmi/commands/watchdog.py | 92 |
25 files changed, 3885 insertions, 0 deletions
diff --git a/pyipmi/commands/__init__.py b/pyipmi/commands/__init__.py new file mode 100644 index 0000000..380aaf6 --- /dev/null +++ b/pyipmi/commands/__init__.py @@ -0,0 +1,89 @@ +# 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. + + +"""IPMI commands that are implemented + +These don't always map directly to IPMI requests, although sometimes +they do. Sometimes, they map to higher level commands provided by +ipmitool. It's more convenient (and closer to real world use) to use +these higher level commands than to break stuff down. +""" +from chassis import chassis_commands +from bmc import bmc_commands +from sdr import sdr_commands +from fw import fw_commands +from sel import sel_commands +from sol import sol_commands +from payload import payload_commands +from dcmi import dcmi_commands +from pef import pef_commands +from freeipmi_pef import freeipmi_pef_commands +from pet import pet_commands +from event import event_commands +from watchdog import watchdog_commands +from fru import fru_commands +from lan import lan_commands +from channel import channel_commands +from user import user_commands +from fabric import fabric_commands +from fabric_config import fabric_config_commands +from bootdev import bootdev_commands +from bootparam import bootparam_commands +from mc import mc_commands +from data import data_commands +from info import info_commands + +ipmi_commands = {} + +ipmi_commands.update(bmc_commands) +ipmi_commands.update(chassis_commands) +ipmi_commands.update(sdr_commands) +ipmi_commands.update(fw_commands) +ipmi_commands.update(sel_commands) +ipmi_commands.update(sol_commands) +ipmi_commands.update(payload_commands) +ipmi_commands.update(dcmi_commands) +ipmi_commands.update(pef_commands) +ipmi_commands.update(freeipmi_pef_commands) +ipmi_commands.update(pet_commands) +ipmi_commands.update(event_commands) +ipmi_commands.update(watchdog_commands) +ipmi_commands.update(fru_commands) +ipmi_commands.update(lan_commands) +ipmi_commands.update(channel_commands) +ipmi_commands.update(user_commands) +ipmi_commands.update(fabric_commands) +ipmi_commands.update(fabric_config_commands) +ipmi_commands.update(bootdev_commands) +ipmi_commands.update(bootparam_commands) +ipmi_commands.update(mc_commands) +ipmi_commands.update(data_commands) +ipmi_commands.update(info_commands) diff --git a/pyipmi/commands/bmc.py b/pyipmi/commands/bmc.py new file mode 100644 index 0000000..3a91569 --- /dev/null +++ b/pyipmi/commands/bmc.py @@ -0,0 +1,152 @@ +# 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. + + +"""BMC related commands""" + +from .. import Command +from .. bmc import BMCInfo, BMCGuid, BMCEnables, BMCResult, BMCResetResult +from pyipmi.tools.responseparser import ResponseParserMixIn, str2bool + +class GetDeviceIdCommand(Command, ResponseParserMixIn): + """Describes the get_device_id IPMI command + + This is "bmc info" to ipmitool + """ + name = "Get Device ID" + result_type = BMCInfo + + response_fields = { + "Device ID" : {}, + "Device Revision" : {}, + "Firmware Revision" : {}, + "IPMI Version" : {}, + "Manufacturer ID" : {}, + "Product ID" : { "parser" : lambda s: s.split(' ')[0] }, + "Device Available" : { "parser" : str2bool } + } + + ipmitool_args = ["bmc", "info"] + + +class BMCSelfTestCommand(Command, ResponseParserMixIn): + """Describes the get self test results IPMI command + + This is "bmc selftest" to ipmitool + """ + name = "BMC Self Test" + result_type = BMCResult + + response_fields = { + "Selftest" : { } + } + + ipmitool_args = ["bmc", "selftest"] + + +class GetSystemGuidCommand(Command, ResponseParserMixIn): + """Describes the get_system_guid IPMI command + + This is "bmc guid" to ipmitool + """ + name = "Get System GUID" + result_type = BMCGuid + + response_fields = { + "System GUID" : {} + } + + ipmitool_args = ["bmc", "guid"] + +class GetCommandEnables(Command, ResponseParserMixIn): + """The Get Command Enables command + + In ipmitool world, this is "bmc getenables" + """ + name = 'Get Command Enables' + result_type = BMCEnables + + response_fields = { + 'Receive Message Queue Interrupt' : { + 'attr' : 'recv_msg_intr', + 'parser' : str2bool + }, + 'Event Message Buffer Full Interrupt' : { + 'attr' : 'event_msg_intr', + 'parser' : str2bool + }, + 'Event Message Buffer' : { + 'attr' : 'event_msg', + 'parser' : str2bool + }, + 'System Event Logging' : { + 'attr' : 'system_event_log', + 'parser' : str2bool + }, + 'OEM 0' : { + 'attr' : 'oem0', + 'parser' : str2bool + }, + 'OEM 1' : { + 'attr' : 'oem1', + 'parser' : str2bool + }, + 'OEM 2' : { + 'attr' : 'oem2', + 'parser' : str2bool + } + } + + ipmitool_args = ['bmc', 'getenables'] + + +class BMCResetCommand(Command, ResponseParserMixIn): + """The Get Command Enables command + + In ipmitool world, this is "bmc reset [warm|cold]" + """ + name = 'BMC Reset' + result_type = BMCResetResult + + response_fields = { + } + + @property + def ipmitool_args(self): + return ['bmc', 'reset', self._params['type']] + + +bmc_commands = { + 'get_device_id' : GetDeviceIdCommand, + 'get_system_guid' : GetSystemGuidCommand, + 'get_command_enables' : GetCommandEnables, + 'selftest' : BMCSelfTestCommand, + 'bmc_reset' : BMCResetCommand +} diff --git a/pyipmi/commands/bootdev.py b/pyipmi/commands/bootdev.py new file mode 100644 index 0000000..3be6b45 --- /dev/null +++ b/pyipmi/commands/bootdev.py @@ -0,0 +1,80 @@ +# 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. + + +from .. import Command +from pyipmi.tools.responseparser import ResponseParserMixIn +from pyipmi.bootdev import * +from pyipmi.commands.bootparam import * + +class BootDevSetCommand(Command, ResponseParserMixIn): + """ Set Boot Device using ipmitool chassis bootdev """ + + name = "Set Boot Device" + result_type = BootDevSetResult + + response_fields = { + 'Boot Device' : {} + } + + @property + def ipmitool_args(self): + if self._params['options'] != None: + options = "options=" + str(self._params['options']) + return ["chassis", "bootdev", self._params['device'],options] + return ["chassis", "bootdev", self._params['device']] + +class BootDevGetCommand(Command, ResponseParserMixIn): + """ Get Boot Device using ipmitool chassis bootdev """ + + name = "Get Boot Device" + result_type = BootDevGetResult + """ parse the output into a nice harsh""" + + def parse_response(self, out, err): + """ Use bootParam parse method to do the job of parsing output into a nice harsh """ + boot_param = BootParamGetCommand(self._tool) + all_info = boot_param.parse_response(out=out,err=err) + bool2str = {True:'Yes',False:'No'} + + """ Only interested in Device and Persistent (Y/N)""" + device = all_info['Boot Device Selector'] + persistent = (all_info['Options apply'] == 'all future boots') + return {'device':device, 'persistent':bool2str[persistent]} + + """Get 5 from bootparam provides the status of bootdev""" + @property + def ipmitool_args(self): + return ["chassis", "bootparam", "get", "5"] + +bootdev_commands = { + "bootdev_get" : BootDevGetCommand, + "bootdev_set" : BootDevSetCommand +} diff --git a/pyipmi/commands/bootparam.py b/pyipmi/commands/bootparam.py new file mode 100644 index 0000000..08612c6 --- /dev/null +++ b/pyipmi/commands/bootparam.py @@ -0,0 +1,66 @@ +# 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. + + +from .. import Command +from pyipmi.tools.responseparser import ResponseParserMixIn +from pyipmi.bootparam import * + +class BootParamGetCommand(Command, ResponseParserMixIn): + """ Get Boot Parameters using ipmitool chassis bootparam # """ + + name = "Get Boot Device" + result_type = BootParamGetResult + + def parse_response(self, out, err): + """ Output is a number of lines with some info + """ + result = {} + delimiter = [':','is','to'] + for line in out.strip().split('\n'): + key, value = line, "" + for x in delimiter: + if x in line: + info = line.split(x) + key, value = info[0], info[1] + break + key = key.strip(' -') + value = value.strip(' -') + result[key] = value + return result + + """ get #param from bootparam """ + @property + def ipmitool_args(self): + return ["chassis", "bootparam", "get",self._params['param']] + +bootparam_commands = { + "bootparam_get" : BootParamGetCommand +} diff --git a/pyipmi/commands/channel.py b/pyipmi/commands/channel.py new file mode 100644 index 0000000..200e193 --- /dev/null +++ b/pyipmi/commands/channel.py @@ -0,0 +1,201 @@ +# 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. + + +"""channel related commands""" + +from .. import Command +from pyipmi.channel import * +from pyipmi.tools.responseparser import ResponseParserMixIn +import re + + +class ChannelInfoCommand(Command, ResponseParserMixIn): + """Describes the get channel info IPMI command + + This is "channel info" to ipmitool + """ + + def parse_response(self, out, err): + """ Strip out extraneous colons to allow more generic parsing + """ + out_list = map(lambda x: x.strip(), out.split('\n')) + new_out_list = [] + + setting_prefix = 'Active' + for line in out_list: + m = re.match("Channel 0x([0-9a-fA-F]+) info:", line) + if m: + line = "Channel : %s" % m.group(1) + + m = re.match("(Alerting|Per-message Auth|User Level Auth|Access Mode)\s+:\s+(\S+)", line) + if m: + line = "%s %s : %s" % (setting_prefix, m.group(1), m.group(2)) + + m = re.match("Volatile\(active\) Settings", line) + if m: + setting_prefix = 'Active' + continue + + m = re.match("Non-Volatile Settings", line) + if m: + setting_prefix = 'NV' + continue + + new_out_list.append(line) + + new_out = '\n'.join(new_out_list) + return self.response_parser(new_out, err) + + name = "Channel Info" + result_type = ChannelInfoResult + + response_fields = { + 'Channel' : {}, + 'Channel Medium Type' : {}, + 'Channel Protocol Type' : {}, + 'Session Support' : {}, + 'Active Session Count' : {}, + 'Protocol Vendor ID' : {}, + 'Active Alerting' : {}, + 'Active Per-message Auth' : {}, + 'Active User Level Auth' : {}, + 'Active Access Mode' : {}, + 'NV Alerting' : {}, + 'NV Per-message Auth' : {}, + 'NV User Level Auth' : {}, + 'NV Access Mode' : {} + } + + ipmitool_args = ["channel", "info"] + + +class ChannelGetAccessCommand(Command, ResponseParserMixIn): + """Describes the get channel access IPMI command + + This is "channel getaccess" to ipmitool + """ + + response_parser = ResponseParserMixIn.parse_colon_record_list + + name = "Channel Get Access" + result_type = ChannelGetAccessResult + + response_fields = { + 'Maximum User IDs' : {}, + 'Enabled User IDs' : {}, + 'User ID' : {}, + 'User Name' : {}, + 'Fixed Name' : {}, + 'Access Available' : {}, + 'Link Authentication' : {}, + 'IPMI Messaging' : {}, + 'Privilege Level' : {} + } + + @property + def ipmitool_args(self): + """ + """ + return ["channel", "getaccess", self._params['channel'], + self._params['userid']] + + +class ChannelSetAccessCommand(Command, ResponseParserMixIn): + """Describes the set channel access IPMI command + + This is "channel setaccess" to ipmitool + """ + + name = "Channel Set Access" + result_type = ChannelSetAccessResult + + response_fields = { + } + + @property + def ipmitool_args(self): + callin = ipmi = link = priv_level = "" + + if self._params.get('callin'): + callin = "callin=%s" % self._params.get('callin') + if self._params.get('ipmi'): + ipmi = "ipmi=%s" % self._params.get('ipmi') + if self._params.get('link'): + link = "link=%s" % self._params.get('link') + if self._params.get('priv_level'): + priv_level = "privilege=%s" % self._params.get('priv_level') + + return ["channel", "setaccess", self._params['channel'], + self._params['userid'], callin, ipmi, link, priv_level] + + +class ChannelGetCiphersCommand(Command, ResponseParserMixIn): + """Describes the get channel cipher suites IPMI command + + This is "channel getciphers <ipmi | sol>" to ipmitool + """ + + def parse_response(self, out, err): + """ Strip out extraneous colons to allow more generic parsing + """ + out.strip() + output_list = map(lambda x: x.strip(), out.split('\n')) + result = {} + + for line in output_list: + if line == '': + continue + line_list = map(lambda x: x.strip(), line.split()) + if line_list[0] == 'ID': + continue + suite = line_list[0] + result[suite] = ChannelGetCiphersResult() + result[suite].iana = line_list[1] + result[suite].auth_alg = line_list[2] + result[suite].integrity_alg = line_list[3] + result[suite].confidentiality_alg = line_list[4] + + return result + + name = "Channel Get Cipher Suites" + result_type = ChannelGetCiphersResult + + @property + def ipmitool_args(self): + return ["channel", "getciphers", self._params['mode']] + + +channel_commands = { + 'channel_info' : ChannelInfoCommand, + 'channel_get_access' : ChannelGetAccessCommand, + 'channel_set_access' : ChannelSetAccessCommand, + 'channel_get_ciphers' : ChannelGetCiphersCommand +} diff --git a/pyipmi/commands/chassis.py b/pyipmi/commands/chassis.py new file mode 100644 index 0000000..1845902 --- /dev/null +++ b/pyipmi/commands/chassis.py @@ -0,0 +1,80 @@ +# 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. + + +"""Chassis related IPMI commands""" +from .. import Command +from .. chassis import ChassisStatus +from pyipmi.tools.responseparser import ResponseParserMixIn, str2bool + +class ChassisStatusCommand(Command, ResponseParserMixIn): + """Describes the chassis status IPMI command""" + + name = 'Chassis Status' + + ipmitool_args = ['chassis', 'status'] + result_type = ChassisStatus + + response_fields = { + 'System Power' : {'attr' : 'power_on', 'parser' : lambda v: v == 'on'}, + 'Power Overload' : {'parser' : str2bool}, + 'Power Interlock' : {}, + 'Main Power Fault' : {'parser' : str2bool}, + 'Power Control Fault' : {'parser' : str2bool}, + 'Power Restore Policy' : {} + } + +class ChassisControlCommand(Command, ResponseParserMixIn): + """Describes the IPMI chassis control command + + ipmitool calls this "chassis power" + """ + + @property + def ipmitool_args(self): + """The chassis control command takes a 'mode' parameter + + Look at ipmitool's manpage for more info. + """ + return ['chassis', 'power', self._params['mode']] + +class ChassisPolicyCommand(Command, ResponseParserMixIn): + """Describes the IPMI chassis policy command""" + + @property + def ipmitool_args(self): + """The chassis policy command takes a 'state' parameter""" + return ['chassis', 'policy', self._params['state']] + +chassis_commands = { + 'chassis_status' : ChassisStatusCommand, + 'chassis_control' : ChassisControlCommand, + 'chassis_policy' : ChassisPolicyCommand +} diff --git a/pyipmi/commands/data.py b/pyipmi/commands/data.py new file mode 100644 index 0000000..5fe5b1b --- /dev/null +++ b/pyipmi/commands/data.py @@ -0,0 +1,125 @@ +# 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. + + +from .. import Command +from pyipmi.tools.responseparser import ResponseParserMixIn +from pyipmi.data import * + +class DataMemReadCommand(Command, ResponseParserMixIn): + """ Describes the cxoem data mem read command + """ + + name = "Read value from memory" + result_type = DataMemReadResult + + response_fields = { + 'Length' : {}, + 'Addr' : {}, + 'Value' : {} + } + + @property + def ipmitool_args(self): + args = ["cxoem", "data", "mem", "read", + self._params['length'], self._params['addr']] + if self._params['fmt']: + args.append(self._params['fmt']) + return args + + +class DataMemWriteCommand(Command, ResponseParserMixIn): + """ Describes the cxoem data mem write command + """ + + name = "Write value to memory" + result_type = DataMemWriteResult + + response_fields = { + 'Length' : {}, + 'Addr' : {}, + 'Value' : {} + } + + @property + def ipmitool_args(self): + return ["cxoem", "data", "mem", "write", self._params['length'], + self._params['addr'], self._params['value']] + + +class DataCDBReadCommand(Command, ResponseParserMixIn): + """ Describes the cxoem data cdb read command + """ + + name = "Read value from CDB" + result_type = DataCDBReadResult + + response_fields = { + 'Length' : {}, + 'Cid' : {}, + 'Data size' : {}, + 'CID size' : {}, + 'Value' : {} + } + + @property + def ipmitool_args(self): + args = ["cxoem", "data", "cdb", "read", + self._params['length'], self._params['cid']] + if self._params['fmt']: + args.append(self._params['fmt']) + return args + + +class DataCDBWriteCommand(Command, ResponseParserMixIn): + """ Describes the cxoem data cdb write command + """ + + name = "Write value to CDB" + result_type = DataCDBWriteResult + + response_fields = { + 'Length' : {}, + 'Cid' : {}, + 'Value' : {} + } + + @property + def ipmitool_args(self): + return ["cxoem", "data", "cdb", "write", self._params['length'], + self._params['cid'], self._params['value']] + + +data_commands = { + "data_memread" : DataMemReadCommand, + "data_memwrite" : DataMemWriteCommand, + "data_cdbread" : DataCDBReadCommand, + "data_cdbwrite" : DataCDBWriteCommand +} diff --git a/pyipmi/commands/dcmi.py b/pyipmi/commands/dcmi.py new file mode 100644 index 0000000..31c8a8f --- /dev/null +++ b/pyipmi/commands/dcmi.py @@ -0,0 +1,337 @@ +# 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. + + +from .. import Command +from pyipmi.tools.responseparser import * +from pyipmi.dcmi import * + +class DCMICommandWithErrors(Command, ResponseParserMixIn): + + # TODO: Generalize this to base class? Better way to include + # error output in parsing? + def parse_response(self, out, err): + """Parse the response to a command + + The 'response_format' attribute is used to determine + what parser to use to for interpreting the results. + + Arguments: + out -- the text response of a command from stdout + err -- the text response of a command from stderr + """ + + out = out + err + return self.response_parser(out, err) + +class DCMIGetCapabilitiesCommand(DCMICommandWithErrors): + """Describes the DCMI get capabilities command + + """ + + name = "Get DCMI Capabilities" + result_type = DCMIGetCapabilitiesResult + + response_fields = { + 'DCMI Specification Conformance' : {}, + 'Identification Support' : {}, + 'SEL logging' : {}, + 'Chassis Power' : {}, + 'Temperature Monitor' : {}, + 'Power Management / Monitoring Support' : {}, + 'In-band System Interface Channel' : {}, + 'Serial TMODE' : {}, + 'Out-Of-Band Secondary LAN Channel' : {}, + 'Out-Of-Band Primary LAN Channel' : {}, + 'SOL' : {}, + 'VLAN' : {}, + 'Number of SEL entries' : {}, + 'SEL automatic rollover' : {}, + 'GUID' : {}, + 'DHCP Host Name' : {}, + 'Asset Tag' : {}, + 'Inlet temperature' : {}, + 'Processors temperature' : {}, + 'Baseboard temperature' : {}, + 'Power Management Device Slave Address' : {}, + 'Power Management Controller Device Revision' : {}, + 'Power Management Controller Channel Number' : {}, + 'Primary LAN Out-of-band Channel Number' : {}, + 'Secondary LAN Out-of-band Channel Number' : {}, + 'Serial Out-of-band TMODE Capability Channel Number' : {} + } + + ipmidcmi_args = ["--get-dcmi-capability-info"] + +class DCMISetAssetTagCommand(DCMICommandWithErrors): + """Describes the DCMI set asset tag command + + """ + + name = "Set DCMI Asset Tag" + result_type = DCMISetAssetTagResult + + # No response -- Have to do a get to confirm + response_fields = { + } + + @property + def ipmidcmi_args(self): + """ + """ + return ["--set-asset-tag", self._params['tag']] + +class DCMIGetAssetTagCommand(DCMICommandWithErrors): + """Describes the dcmi get asset tag command + + """ + + response_parser = ResponseParserMixIn.parse_single_line + + name = "Get DCMI Asset Tag" + result_type = DCMIGetAssetTagResult + + response_fields = { + 'attr' : 'tag' + } + + ipmidcmi_args = ["--get-asset-tag"] + + +class DCMIGetManagementControllerID(DCMICommandWithErrors): + """Describes the DCMI get management controller ID string command + + """ + + response_parser = ResponseParserMixIn.parse_single_line + + name = "Get Management Controller ID String" + result_type = DCMIGetManagementControllerIDResult + + response_fields = { + 'attr' : 'DCMI' + } + + ipmidcmi_args = ["--get-management-controller-identifier-string"] + +class DCMISetManagementControllerID(DCMICommandWithErrors): + """Describes the DCMI get management controller ID string command + + """ + response_parser = ResponseParserMixIn.parse_single_line + + name = "Set Management Controller ID String" + result_type = DCMISetManagementControllerIDResult + + response_fields = { + 'attr' : 'DCMI' + } + + @property + def ipmidcmi_args(self): + """ + """ + return ["--set-management-controller-identifier-string", self._params['controller']] +class DCMIGetSensorInfo(DCMICommandWithErrors): + """Describes the DCMI get sensor info command + + """ + def parse_response(self, out, err): + """ Output is a number of lines with some info + """ + new_out_list = [] + expected_fields = ['Inlet Temperature','CPU Temperature','Baseboard temperature'] + for line in out.strip().split('\n'): + for field in expected_fields: + if field in line: + value = line.lstrip(field) + new_line = field + " : " + value + new_out_list.append(new_line) + new_output= "\n".join(new_out_list) + return self.response_parser(new_output, err) + + name = "Get DCMI Sensor Info" + result_type = DCMIGetSensorInfoResult + response_fields = { + 'Inlet Temperature':{}, + 'CPU Temperature' : {}, + 'Baseboard temperature' :{} + } + + + ipmidcmi_args = ["--get-dcmi-sensor-info"] + + +class DCMIGetPowerStatistics(DCMICommandWithErrors): + """Describes the DCMI get system power statistics command + + """ + + name = "Get Power Statistics" + result_type = DCMIGetPowerStatisticsResult + + response_fields = { + 'Current Power' : {}, + 'Minimum Power over sampling duration' : {}, + 'Maximum Power over sampling duration' : {}, + 'Average Power over sampling duration' : {}, + 'Time Stamp' : {}, + 'Statistics reporting time period' : {}, + 'Power Measurement' : {} + } + + ipmidcmi_args = ["--get-system-power-statistics"] + + +class DCMIGetPowerLimit(DCMICommandWithErrors): + """Describes the DCMI get power limit command + + """ + name = "Get Power Limit" + result_type = DCMIGetPowerLimitResult + + response_fields = { + 'Exception Actions' : {} , + 'Power Limit Requested' : {}, + 'Correction time limit' : {}, + 'Management application Statistics Sampling period' :{} + } + + ipmidcmi_args = ["--get-power-limit"] + + +class DCMISetPowerLimit(DCMICommandWithErrors): + """Describes the DCMI set power limit command + + """ + + name = "Set Power Limit" + result_type = DCMISetPowerLimitResult + + response_fields = { + } + + ipmidcmi_args = ["--set-power-limit"] + +class DCMIPowerLimitRequested(DCMICommandWithErrors): + """Describes the DCMI power limit requested command + + """ + + name = "Power Limit Requested (Watts)" + result_type = DCMIPowerLimitRequestedResult + + response_fields = { + } + + @property + def ipmidcmi_args(self): + """ """ + if self._params['exception'] is None: + return ["--set-power-limit","--power-limit-requested", self._params['limit']] + else: + return ["--set-power-limit","--power-limit-requested", self._params['limit'], + "--exception-actions", self._params['exception']] + +class DCMICorrectionTimeLimit(DCMICommandWithErrors): + """Describes the DCMI correction time limit command + + """ + + name = "Power Correction Time Limit (Milliseconds)" + result_type = DCMICorrectionTimeLimitResult + + response_fields = { + } + + @property + def ipmidcmi_args(self): + """ + """ + if self._params['exception'] is None: + return ["--set-power-limit","--correction-time-limit", self._params['time_limit']] + else: + return ["--set-power-limit","--correction-time-limit", self._params['time_limit'], + "--exception-actions", self._params['exception']] + +class DCMIStatisticsSamplingPeriod(DCMICommandWithErrors): + """Describes the DCMI statistics sampling period command + + """ + name = "Power Statistics Sampling Period ( seconds)" + result_type = DCMIStatisticsSamplingPeriodResult + + response_fields = { + } + + @property + def ipmidcmi_args(self): + """ """ + if self._params['exception'] is None: + return ["--set-power-limit","--statistics-sampling-period", self._params['period']] + else: + return ["--set-power-limit","--statistics-sampling-period", self._params['period'], + "--exception-actions", self._params['exception']] + + +class DCMIActivatePowerLimit(DCMICommandWithErrors): + """Describes the DCMI activate/deactivate power limit command + + """ + + response_parser = ResponseParserMixIn.parse_single_line + + name = "Activate Or Deactivate Power Limit" + result_type = DCMIActivatePowerLimitResult + + response_fields = { + } + + @property + def ipmidcmi_args(self): + """ + """ + return ["--activate-deactivate-power-limit", self._params['action']] + +dcmi_commands = { + "dcmi_get_capabilities" : DCMIGetCapabilitiesCommand, + "dcmi_set_asset_tag" : DCMISetAssetTagCommand, + "dcmi_get_asset_tag" : DCMIGetAssetTagCommand, + "dcmi_get_controller_id" : DCMIGetManagementControllerID, + "dcmi_set_controller_id" : DCMISetManagementControllerID, + "dcmi_get_sensor_info" : DCMIGetSensorInfo, + "dcmi_get_power_statistics" : DCMIGetPowerStatistics, + "dcmi_get_power_limit" : DCMIGetPowerLimit, + "dcmi_set_power_limit" : DCMISetPowerLimit, + "dcmi_power_limit_requested": DCMIPowerLimitRequested, + "dcmi_activate_power_limit" : DCMIActivatePowerLimit, + "dcmi_correction_time_limit" : DCMICorrectionTimeLimit, + "dcmi_statistics_sampling_period": DCMIStatisticsSamplingPeriod +} diff --git a/pyipmi/commands/event.py b/pyipmi/commands/event.py new file mode 100644 index 0000000..2aca6dc --- /dev/null +++ b/pyipmi/commands/event.py @@ -0,0 +1,79 @@ +# 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. + + +"""event related commands -- for generating test events""" + +from .. import Command +from pyipmi.event import * +from pyipmi.tools.responseparser import ResponseParserMixIn + + +class GenerateGenericEvent(Command, ResponseParserMixIn): + """Describes the generic event IPMI command + + This is "event <event_type>" to ipmitool + """ + name = "Generate Generic Event" + result_type = GenericEventResult + + response_fields = { + } + + @property + def ipmitool_args(self): + """ + """ + return ["event", self._params['event_type']] + + +class AssertSensorEvent(Command, ResponseParserMixIn): + """Describes the generic event IPMI command + + This is "event <sensorid> <state> assert" to ipmitool + """ + name = "Assert Sensor Event" + result_type = AssertSensorEventResult + + response_fields = { + } + + @property + def ipmitool_args(self): + """ + """ + return ["event", self._params['sensor_id'], + self._params['state'], 'assert'] + + +event_commands = { + 'generic_event' : GenerateGenericEvent, + 'assert_sensor_event' : AssertSensorEvent +} diff --git a/pyipmi/commands/fabric.py b/pyipmi/commands/fabric.py new file mode 100644 index 0000000..c28a6fb --- /dev/null +++ b/pyipmi/commands/fabric.py @@ -0,0 +1,306 @@ +# 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 holdes cxoem "fabric" commands other than "fabric config" +commands. +""" + +from .. import Command +from pyipmi.tools.responseparser import ResponseParserMixIn +from pyipmi.fabric import * +from pyipmi import IpmiError + +class CommandWithErrors(Command, ResponseParserMixIn): + + def parse_response(self, out, err): + """Parse the response to a command + + The 'ipmitool_response_format' attribute is used to determine + what parser to use to for interpreting the results. + + Arguments: + out -- the text response of an command from stdout + err -- the text response of an command from stderr + """ + + out = out + err + return self.response_parser(out, err) + +class UpdateConfigCommand(Command, ResponseParserMixIn): + """Describes the ipmitool fabric update config command""" + name = "Update Config" + result_type = FabricUpdateConfigResult + + response_fields = { + } + + @property + def ipmitool_args(self): + return ["cxoem", "fabric", "update_config"] + +class GetNodeIDCommand(Command, ResponseParserMixIn): + """Describes the ipmitool fabric get nodeid command""" + name = "Get NodeID command" + result_type = int + + def parse_response(self, out, err): + if err: + raise IpmiError(err) + return int(out) + + response_fields = { + } + + ipmitool_args = ["cxoem", "fabric", "get", "nodeid"] + +class GetIPAddrCommand(Command, ResponseParserMixIn): + """Describes the ipmitool fabric get ipaddr command""" + name = "Get ipaddr command" + result_type = str + + def parse_response(self, out, err): + return out.strip() + + response_fields = { + } + + @property + def ipmitool_args(self): + result = ["cxoem", "fabric", "get", "ipaddr"] + if self._params.get('nodeid', None): + result.extend(['node', self._params['nodeid']]) + if self._params.get('iface', None): + result.extend(['interface', self._params['iface']]) + return result + +class GetMacAddrCommand(Command, ResponseParserMixIn): + """Describes the ipmitool fabric get macaddr command""" + name = "Get macaddr command" + result_type = str + + def parse_response(self, out, err): + if err: + raise IpmiError(err) + return out.strip() + + response_fields = { + } + + @property + def ipmitool_args(self): + result = ["cxoem", "fabric", "get", "macaddr", "interface", + self._params['iface']] + if self._params.get('nodeid', None): + result.extend(['node', self._params['nodeid']]) + return result + +class AddMacAddrCommand(Command, ResponseParserMixIn): + """Describes the ipmitool fabric add macaddr command""" + name = "Add macaddr command" + + @property + def ipmitool_args(self): + result = ['cxoem', 'fabric', 'add', + 'macaddr', self._params['macaddr'], + 'interface', self._params['iface']] + if self._params['nodeid']: + result += ['node', self._params['nodeid']] + return result + + +class RmMacAddrCommand(Command, ResponseParserMixIn): + """Describes the ipmitool fabric rm macaddr command""" + name = "Remove macaddr command" + + @property + def ipmitool_args(self): + result = ['cxoem', 'fabric', 'rm', + 'macaddr', self._params['macaddr'], + 'interface', self._params['iface']] + if self._params['nodeid']: + result += ['node', self._params['nodeid']] + return result + +class GetLinkspeedCommand(Command, ResponseParserMixIn): + """Describes the ipmitool fabric get linkspeed command""" + name = "Get linkspeed command" + result_type = float + + def parse_response(self, out, err): + if err: + raise IpmiError(err) + return float(out) + + @property + def ipmitool_args(self): + result = ['cxoem', 'fabric', 'get', 'linkspeed'] + if self._params.get('link', None): + result.extend(['link', self._params['link']]) + if self._params.get('actual', None): + result.extend(['actual']) + return result + +class GetLinkStatsCommand(Command, ResponseParserMixIn): + """Describes the ipmitool fabric info link_stats command""" + name = "Get link_stats command" + result_type = FabricGetLinkStatsResult + response_fields = { + 'File Name' : {}, + 'Error' : {} + } + + def parse_response(self, out, err): + return out.strip() + + @property + def ipmitool_args(self): + if self._params['tftp_addr'] != None: + tftp_args = self._params['tftp_addr'].split(":") + if len(tftp_args) == 1: + return [ + 'cxoem', 'fabric', 'info', 'link_stats', + 'link', self._params['link'], + 'tftp', tftp_args[0], + 'file', self._params['filename'] + ] + else: + return [ + 'cxoem', 'fabric', 'info', 'link_stats', + 'link', self._params['link'], + 'tftp', tftp_args[0], + 'port', tftp_args[1], + 'file', self._params['filename'] + ] + else: + return [ + 'cxoem', 'fabric', 'info', 'link_stats', + 'link', self._params['link'], + 'file', self._params['filename'] + ] + +class GetLinkMapCommand(Command, ResponseParserMixIn): + """Describes the ipmitool fabric info linkmap command""" + name = "Get linkmap command" + result_type = FabricGetLinkMapResult + response_fields = { + 'File Name' : {}, + 'Error' : {} + } + + def parse_response(self, out, err): + return out.strip() + + @property + def ipmitool_args(self): + if self._params['tftp_addr'] != None: + tftp_args = self._params['tftp_addr'].split(":") + if len(tftp_args) == 1: + return ["cxoem", "fabric", "info", "linkmap", "tftp", + tftp_args[0], "file", self._params['filename']] + else: + return ["cxoem", "fabric", "info", "linkmap", "tftp", + tftp_args[0], "port", tftp_args[1], "file", + self._params['filename']] + else: + return ["cxoem", "fabric", "info", "linkmap", "file", + self._params['filename']] + +class GetRoutingTableCommand(Command, ResponseParserMixIn): + """Describes the ipmitool fabric info routing_table command""" + name = "Get routing_table command" + result_type = FabricGetRoutingTableResult + response_fields = { + 'File Name' : {}, + 'Error' : {} + } + + def parse_response(self, out, err): + return out.strip() + + @property + def ipmitool_args(self): + if self._params['tftp_addr'] != None: + tftp_args = self._params['tftp_addr'].split(":") + if len(tftp_args) == 1: + return ["cxoem", "fabric", "info", "routing_table", "tftp", + tftp_args[0], "file", self._params['filename']] + else: + return ["cxoem", "fabric", "info", "routing_table", "tftp", + tftp_args[0], "port", tftp_args[1], "file", + self._params['filename']] + else: + return ["cxoem", "fabric", "info", "routing_table", "file", + self._params['filename']] + +class GetDepthChartCommand(Command, ResponseParserMixIn): + """Describes the ipmitool fabric info depth_chart command""" + name = "Get depth_chart command" + result_type = FabricGetDepthChartResult + response_fields = { + 'File Name' : {}, + 'Error' : {} + } + + def parse_response(self, out, err): + return out.strip() + + @property + def ipmitool_args(self): + if self._params['tftp_addr'] != None: + tftp_args = self._params['tftp_addr'].split(":") + if len(tftp_args) == 1: + return ["cxoem", "fabric", "info", "depth_chart", "tftp", + tftp_args[0], "file", self._params['filename']] + else: + return ["cxoem", "fabric", "info", "depth_chart", "tftp", + tftp_args[0], "port", tftp_args[1], "file", + self._params['filename']] + else: + return ["cxoem", "fabric", "info", "depth_chart", "file", + self._params['filename']] + +fabric_commands = { + "fabric_updateconfig" :UpdateConfigCommand, + "fabric_getnodeid" : GetNodeIDCommand, + "fabric_getipaddr" : GetIPAddrCommand, + "fabric_getmacaddr" : GetMacAddrCommand, + "fabric_getlinkspeed" : GetLinkspeedCommand, + "fabric_getlinkstats" : GetLinkStatsCommand, + "fabric_getlinkmap" : GetLinkMapCommand, + "fabric_getdepthchart" : GetDepthChartCommand, + "fabric_getroutingtable" : GetRoutingTableCommand, + "fabric_addmacaddr" : AddMacAddrCommand, + "fabric_rmmacaddr" : RmMacAddrCommand, + + "fabric_info_getroutingtable" : GetRoutingTableCommand, + "fabric_info_getlinkmap" : GetLinkMapCommand, + "fabric_info_getdepthchart" : GetDepthChartCommand, +} diff --git a/pyipmi/commands/fabric_config.py b/pyipmi/commands/fabric_config.py new file mode 100644 index 0000000..fe6b92f --- /dev/null +++ b/pyipmi/commands/fabric_config.py @@ -0,0 +1,288 @@ +# 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. + + +from .. import Command +from pyipmi.tools.responseparser import ResponseParserMixIn +from pyipmi.fabric import * +from pyipmi import IpmiError + +class CommandWithErrors(Command, ResponseParserMixIn): + + def parse_response(self, out, err): + """Parse the response to a command + + The 'ipmitool_response_format' attribute is used to determine + what parser to use to for interpreting the results. + + Arguments: + out -- the text response of an command from stdout + err -- the text response of an command from stderr + """ + + out = out + err + return self.response_parser(out, err) + +class GetIPInfoCommand(CommandWithErrors): + """ Describes the cxoem fabric list_ip_addrs IPMI command + """ + + name = "Retrieve fabric IP info" + result_type = FabricGetIPInfoResult + + response_fields = { + 'File Name' : {}, + 'Error' : {} + } + + @property + def ipmitool_args(self): + if self._params['tftp_addr'] != None: + tftp_args = self._params['tftp_addr'].split(":") + if len(tftp_args) == 1: + return ["cxoem", "fabric", "config", "get", "ipinfo", "tftp", + tftp_args[0], "file", self._params['filename']] + else: + return ["cxoem", "fabric", "config", "get", "ipinfo", "tftp", + tftp_args[0], "port", tftp_args[1], "file", + self._params['filename']] + else: + return ["cxoem", "fabric", "config", "get", "ipinfo", "file", + self._params['filename']] + +class GetUplinkInfoCommand(CommandWithErrors): + """ Describes the cxoem fabric list_ip_addrs IPMI command + """ + + name = "Retrieve fabric Uplink info" + result_type = FabricGetUplinkInfoResult + + response_fields = { + 'File Name' : {}, + 'Error' : {} + } + + @property + def ipmitool_args(self): + if self._params['tftp_addr'] != None: + tftp_args = self._params['tftp_addr'].split(":") + if len(tftp_args) == 1: + return ["cxoem", "fabric", "config", "get", "uplink_info", + "tftp", tftp_args[0], "file", self._params['filename']] + else: + return ["cxoem", "fabric", "config", "get", "uplink_info", + "tftp", tftp_args[0], "port", tftp_args[1], "file", + self._params['filename']] + else: + return ["cxoem", "fabric", "config", "get", "uplink_info", "file", + self._params['filename']] + +class GetMACAddressesCommand(CommandWithErrors): + """ Describes the cxoem fabric list_macs IPMI command + """ + + name = "Retrieve fabric MAC addresses" + result_type = FabricGetMACAddressesResult + + response_fields = { + 'File Name' : {}, + 'Error' : {} + } + + @property + def ipmitool_args(self): + if self._params['tftp_addr'] != None: + tftp_args = self._params['tftp_addr'].split(":") + if len(tftp_args) == 1: + return ["cxoem", "fabric", "config", "get", "macaddrs", "tftp", + tftp_args[0], "file", self._params['filename']] + else: + return ["cxoem", "fabric", "config", "get", "macaddrs", "tftp", + tftp_args[0], "port", tftp_args[1], "file", + self._params['filename']] + else: + return ["cxoem", "fabric", "config", "get", "macaddrs", "file", + self._params['filename']] + +class UpdateConfigCommand(Command, ResponseParserMixIn): + """Describes the ipmitool fabric config update config command""" + name = "Update Config" + + ipmitool_args = ['cxoem', 'fabric', 'config', 'update_config'] + +class GetIPSrcCommand(Command, ResponseParserMixIn): + """Describes the ipmitool fabric get ipsrc command""" + name = "Get ipsrc command" + result_type = int + + def parse_response(self, out, err): + return int(out) + + response_fields = { + } + + @property + def ipmitool_args(self): + return ["cxoem", "fabric", "config", "get", "ipsrc"] + +class SetIPSrcCommand(Command, ResponseParserMixIn): + """Describes the ipmitool fabric set ipsrc command""" + name = "Set ipsrc command" + + @property + def ipmitool_args(self): + return ['cxoem', + 'fabric', + 'config', + 'set', + 'ipsrc', + self._params['ipsrc_mode']] + +class FactoryDefaultCommand(Command, ResponseParserMixIn): + """Describes the ipmitool fabric config factory_default command""" + name = "Fabric config factory_default command" + + ipmitool_args = ['cxoem', 'fabric', 'config', 'factory_default'] + +class GetIPAddrBase(Command, ResponseParserMixIn): + """Describes the ipmitool fabric config get ipaddr_base command""" + name = "Get fabric config ipaddr_base command" + result_type = str + + ipmitool_args = ['cxoem', 'fabric', 'config', 'get', 'ipaddr_base'] + + def parse_response(self, out, err): + return out.strip() + +class GetLinkspeedCommand(Command, ResponseParserMixIn): + """Describes the ipmitool fabric config get linkspeed command""" + name = "Get global linkspeed command" + result_type = float + + def parse_response(self, out, err): + if err: + raise IpmiError(err) + return float(out) + + ipmitool_args = ['cxoem', 'fabric', 'config', 'get', 'linkspeed'] + +class SetLinkspeedCommand(Command, ResponseParserMixIn): + """Describes the ipmitool fabric config set linkspeed command""" + name = "Set linkspeed command" + + @property + def ipmitool_args(self): + return ['cxoem', 'fabric', 'config', 'set', 'linkspeed', + self._params['linkspeed']] + +class GetLinkspeedPolicyCommand(Command, ResponseParserMixIn): + """Describes the ipmitool fabric config get ls_policy command""" + name = "Get global ls_policy command" + result_type = int + + def parse_response(self, out, err): + if err: + raise IpmiError(err) + return int(out) + + ipmitool_args = ['cxoem', 'fabric', 'config', 'get', 'ls_policy'] + +class SetLinkspeedPolicyCommand(Command, ResponseParserMixIn): + """Describes the ipmitool fabric config set ls_policy command""" + name = "Set linkspeed command" + + @property + def ipmitool_args(self): + return ['cxoem', 'fabric', 'config', 'set', 'ls_policy', + self._params['ls_policy']] + +class GetUplinkCommand(Command, ResponseParserMixIn): + """Describes the ipmitool fabric config get uplink command""" + name = "Get uplink command" + result_type = int + + def parse_response(self, out, err): + if err: + raise IpmiError(err) + return int(out) + + @property + def ipmitool_args(self): + return ['cxoem', 'fabric', 'config', 'get', 'uplink', 'interface', + self._params['iface']] + +class SetUplinkCommand(Command, ResponseParserMixIn): + """Describes the ipmitool fabric config set uplink command""" + name = "Set uplink command" + + @property + def ipmitool_args(self): + return ['cxoem', 'fabric', 'config', 'set', 'uplink', + self._params['uplink'], 'interface', self._params['iface']] + +class GetLinkUsersFactorCommand(Command, ResponseParserMixIn): + """Describes the ipmitool fabric config get lu_factor command""" + name = "Get global link users factor command" + result_type = int + + def parse_response(self, out, err): + if err: + raise IpmiError(err) + return int(out) + + ipmitool_args = ['cxoem', 'fabric', 'config', 'get', 'lu_factor'] + +class SetLinkUsersFactorCommand(Command, ResponseParserMixIn): + """Describes the ipmitool fabric config set lu_factor command""" + name = "Set global link users factor command" + + @property + def ipmitool_args(self): + return ['cxoem', 'fabric', 'config', 'set', 'lu_factor', + self._params['lu_factor']] + +fabric_config_commands = { + "fabric_config_getipinfo" : GetIPInfoCommand, + "fabric_config_getmacaddresses" : GetMACAddressesCommand, + "fabric_config_updateconfig" : UpdateConfigCommand, + "fabric_config_getipsrc" : GetIPSrcCommand, + "fabric_config_setipsrc" : SetIPSrcCommand, + "fabric_config_factory_default" : FactoryDefaultCommand, + "fabric_config_get_ipaddr_base" : GetIPAddrBase, + "fabric_config_getlinkspeed" : GetLinkspeedCommand, + "fabric_config_setlinkspeed" : SetLinkspeedCommand, + "fabric_config_getlinkspeedpolicy" : GetLinkspeedPolicyCommand, + "fabric_config_setlinkspeedpolicy" : SetLinkspeedPolicyCommand, + "fabric_config_getuplinkinfo" : GetUplinkInfoCommand, + "fabric_config_getuplink" : GetUplinkCommand, + "fabric_config_setuplink" : SetUplinkCommand, + "fabric_config_getlinkusersfactor" : GetLinkUsersFactorCommand, + "fabric_config_setlinkusersfactor" : SetLinkUsersFactorCommand +} diff --git a/pyipmi/commands/freeipmi_pef.py b/pyipmi/commands/freeipmi_pef.py new file mode 100644 index 0000000..a551d65 --- /dev/null +++ b/pyipmi/commands/freeipmi_pef.py @@ -0,0 +1,211 @@ +# 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. + + +"""PEF related commands""" + +from .. import Command +from pyipmi.freeipmi_pef import * +from pyipmi.tools.responseparser import ResponseParserMixIn + + +class FreeIPMIPEFInfoCommand(Command, ResponseParserMixIn): + """Describes the get PEF info IPMI command + + This is "--info" to ipmi-pef-config + """ + name = "Get PEF Info and Capabilities" + result_type = FreeIPMIPEFInfoResult + + response_fields = { + 'PEF version' : {}, + 'Alert action' : {}, + 'Power down action' : {}, + 'Power reset action' : {}, + 'Power cycle action' : {}, + 'OEM action' : {}, + 'Diagnostic interrupt action' : {}, + 'OEM event record filtering' : {}, + 'Number of Event Filter Table entries' : {}, + 'Number of Event Filters' : {}, + 'Number of Alert Policy entries' : {}, + 'Number of Alert Strings' : {} + } + + ipmi_pef_config_args = ['--info'] + + +class FreeIPMIPEFCheckout(Command, ResponseParserMixIn): + """Retrieve platform event filtering configuration + + """ + name = "Checkout PEF Configuration" + + def get_next_line(self, text): + line, c, rest = text.partition('\n') + line = line.strip() + return line, rest + + def parse_section(self, rest): + config_dict = {} + line, rest = self.get_next_line(rest) + while line != "EndSection": + if line[0] == '#': + line, rest = self.get_next_line(rest) + continue + keyname, c, value = line.partition(" ") + config_dict[keyname.strip()] = value.strip() + line, rest = self.get_next_line(rest) + return config_dict, rest + + def parse_results(self, response, err): + """Parse the output from "pef checkout." If a filename was given, + there will be no response + """ + + section_list = {} + line, rest = self.get_next_line(response) + while line != "": + if line[0] == '#': + line, rest = self.get_next_line(rest) + continue + keyword, c, value = line.partition(' ') + if keyword.strip() == "Section": + param_list, rest = self.parse_section(rest) + section_list[value.strip()] = param_list + line, rest = self.get_next_line(rest) + return section_list + + @property + def ipmi_pef_config_args(self): + """ + """ + section = self._params.get("section") + filename = self._params.get('filename') + key = self._params.get('key') + + if filename: + if section: + section = "--section=%s" % section + else: + section = "" + return ["--checkout", "--filename=" + filename, section] + + if key and section: + return ["--checkout", "--key-pair=" + section + ":" + key] + + if section: + return ["--checkout", "--section=" + section] + + return ["--checkout"] + + +class FreeIPMIPEFCommit(Command, ResponseParserMixIn): + + """Update PEF configuration from file or key-value pair + + """ + name = "Update PEF Configuration" + result_type = FreeIPMIPEFCommitResult + + response_fields = { + } + + @property + def ipmi_pef_config_args(self): + """ + """ + filename = self._params.get('filename') + + if filename: + return ["--commit", "--filename=" + filename] + + key_value_pair = self._params.get('key_value_pair') + section = self._params.get('section') + if key_value_pair and section: + return ["--commit", "--key-pair=" + section + ":" + key_value_pair] + + raise Exception("Command pef-config --commit requires either filename or key-value pair") + + +class FreeIPMIPEFDiff(Command, ResponseParserMixIn): + """ Command to diff current PEF configuration against a file or key-value pair + + """ + name = "PEF Diff" + result_type = FreeIPMIDiffResult + + response_fields = { + } + + @property + def ipmi_pef_config_args(self): + """ + """ + filename = self._params.get('filename') + section = self._params.get('section') + key = self._params.get('key') + + if filename: + if section: + section = "--section=%s" % section + else: + section = "" + return ["--diff", "--filename=" + filename, section] + + if key and section: + return ["--diff", "--key-pair=" + section + ":" + key] + + raise Exception("Command pef-config --diff requires either filename or key") + + +class FreeIPMIPEFListSections(Command, ResponseParserMixIn): + """Describes the get PEF list sections command + + """ + name = "List PEF Table Sections" + + def parse_results(self, response, err): + """Parse the output from "--listsections," which is a list + of section names separated by a single line break + """ + result = map(lambda x: x.strip(), response.splitlines()) + return result + + ipmi_pef_config_args = ["--listsections"] + + +freeipmi_pef_commands = { + 'pef_config_info' : FreeIPMIPEFInfoCommand, + 'pef_checkout' : FreeIPMIPEFCheckout, + 'pef_commit' : FreeIPMIPEFCommit, + 'pef_diff' : FreeIPMIPEFDiff, + 'pef_list_sections' : FreeIPMIPEFListSections +} diff --git a/pyipmi/commands/fru.py b/pyipmi/commands/fru.py new file mode 100644 index 0000000..3eb3f87 --- /dev/null +++ b/pyipmi/commands/fru.py @@ -0,0 +1,132 @@ +# 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. + + +"""FRU related commands""" + +from .. import Command +from pyipmi.fru import * +from pyipmi.tools.responseparser import ResponseParserMixIn + + +class FRUPrintCommand(Command, ResponseParserMixIn): + """Describes the FRU get inventory area info IPMI command + + This is "fru print" to ipmitool + """ + name = "FRU Print" + result_type = FRUPrintResult + + response_fields = { + 'FRU Device Description' : {}, + 'Board Mfg Date' : {}, + 'Board Mfg' : {}, + 'Board Product' : {}, + 'Board Serial' : {}, + 'Board Part Number' : {}, + 'Product Manufacturer' : {}, + 'Product Name' : {}, + 'Product Part Number' : {}, + 'Product Serial' : {} + } + + ipmitool_args = ["fru", "print"] + + +class FRUReadCommand(Command, ResponseParserMixIn): + """Describes the FRU read IPMI command + + This is "fru read" to ipmitool + """ + name = "FRU Read" + result_type = FRUReadResult + + response_fields = { + } + + @property + def ipmitool_args(self): + return ["fru", "read", self._params['fru_id'], + self._params['filename']] + + +class FRUWriteCommand(Command, ResponseParserMixIn): + """Describes the FRU write IPMI command + + This is "fru write" to ipmitool + """ + name = "FRU Write" + result_type = FRUWriteResult + + response_fields = { + } + + @property + def ipmitool_args(self): + return ["fru", "read", self._params['fru_id'], + self._params['filename']] + + +class FRUUpgEKeyCommand(Command, ResponseParserMixIn): + """Describes the FRU upgEKey ipmitool command + """ + name = "FRU UpgEkey" + result_type = FRUUpgEKeyResult + + response_fields = { + } + + @property + def ipmitool_args(self): + return ["fru", "upgEkey", self._params['fru_id'], + self._params['filename']] + + +class FRUShowCommand(Command, ResponseParserMixIn): + """Describes the ekanalyzer frushow ipmitool command + """ + name = "FRU Show" + result_type = FRUShowResult + + response_fields = { + } + + @property + def ipmitool_args(self): + return ["ekanalyzer", 'frushow', + 'oc=%s' % self._params['filename']] + + +fru_commands = { + 'fru_print' : FRUPrintCommand, + 'fru_read' : FRUReadCommand, + 'fru_write' : FRUWriteCommand, + 'fru_upg_e_key' : FRUUpgEKeyCommand +} diff --git a/pyipmi/commands/fw.py b/pyipmi/commands/fw.py new file mode 100644 index 0000000..0a70a8e --- /dev/null +++ b/pyipmi/commands/fw.py @@ -0,0 +1,400 @@ +# 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. + + +from .. import Command, IpmiError +from pyipmi.tools.responseparser import ResponseParserMixIn +from pyipmi.fw import * + +class CommandWithErrors(Command, ResponseParserMixIn): + + # TODO: Generalize this to base class? Better way to include + # error output in parsing? + def parse_response(self, out, err): + """Parse the response to a command + + The 'ipmitool_response_format' attribute is used to determine + what parser to use to for interpreting the results. + + Arguments: + out -- the text response of an command from stdout + err -- the text response of an command from stderr + """ + + out = out + err + return self.response_parser(out, err) + +class FWDownloadCommand(CommandWithErrors): + """Describes the cxoem fw download IPMI command + + """ + + name = "Update a Firmware Image" + result_type = FWDownloadResult + + response_fields = { + 'File Name' : {}, + 'Partition' : {}, + 'Slot' : {'attr': 'partition'}, + 'Type' : {}, + 'IP' : {}, + 'TFTP Handle ID' : {}, + 'Start FW download failed' : {'attr': 'fw_error'} + } + + @property + def ipmitool_args(self): + """ + """ + return ["cxoem", "fw", "download", self._params['filename'], + self._params['partition'], self._params['image_type'], + "tftp", self._params['tftp_addr']] + + +class FWUploadCommand(CommandWithErrors): + """Describes the cxoem fw upload IPMI command + + """ + + name = "Retrieve Firmware From Device" + result_type = FWUploadResult + + response_fields = { + 'File Name' : {}, + 'Partition' : {}, + 'Slot' : {'attr': 'partition'}, + 'Type' : {}, + 'IP' : {}, + 'TFTP Handle ID' : {}, + 'Start FW download failed' : {'attr': 'fw_error'} + } + + @property + def ipmitool_args(self): + """ + """ + return ["cxoem", "fw", "upload", self._params['partition'], + self._params['filename'], self._params['image_type'], + "tftp", self._params['tftp_addr']] + + +class FWRegisterReadCommand(CommandWithErrors): + """ cxoem fw register read command """ + name = "Register Firmware Read" + result_type = FWRegisterReadResult + + response_fields = { + 'File Name' : {}, + 'Partition' : {}, + 'Type' : {}, + 'Error' : {} + } + + def parse_response(self, out, err): + result = super(FWRegisterReadCommand, self).parse_response(out, err) + if hasattr(result, "error"): + raise IpmiError(result.error) + + @property + def ipmitool_args(self): + return ["cxoem", "fw", "register", "read", self._params['partition'], + self._params['filename'], self._params['image_type']] + + +class FWRegisterWriteCommand(CommandWithErrors): + """ cxoem fw register write command """ + name = "Register Firmware Write" + result_type = FWRegisterWriteResult + + response_fields = { + 'File Name' : {}, + 'Partition' : {}, + 'Type' : {}, + 'Error' : {} + } + + def parse_response(self, out, err): + result = super(FWRegisterWriteCommand, self).parse_response(out, err) + if hasattr(result, "error"): + raise IpmiError(result.error) + + @property + def ipmitool_args(self): + return ["cxoem", "fw", "register", "write", self._params['partition'], + self._params['filename'], self._params['image_type']] + + +class FWActivateCommand(CommandWithErrors): + """Describes the cxoem fw activate IPMI command + + """ + + name = "Mark A Firmware Image As Active" + result_type = FWActivateResult + + response_fields = { + "" : {} + } + + @property + def ipmitool_args(self): + """ + """ + return ["cxoem", "fw", "activate", self._params['partition']] + + +class FWInvalidateCommand(CommandWithErrors): + """Describes the cxoem fw deactivate IPMI command + + """ + + name = "Mark A Firmware Image As Inactive" + result_type = FWDeactivateResult + + response_fields = { + "" : {} + } + + @property + def ipmitool_args(self): + """ + """ + return ["cxoem", "fw", "invalidate", self._params['partition']] + + +class FWFlagsCommand(CommandWithErrors): + """Describes the cxoem fw flags IPMI command + + """ + + name = "Set Flags For a Firmware Image" + result_type = FWFlagsResult + + response_fields = { + "" : {} + } + + @property + def ipmitool_args(self): + """ + """ + return ["cxoem", "fw", "flags", self._params['partition'], + self._params['flags']] + + +class FWStatusCommand(CommandWithErrors): + """Describes the cxoem fw status IPMI command + + """ + + name = "Check Status of Most Recent Upload or Download" + result_type = FWStatus + + response_fields = { + 'Status' : {}, + 'Error' : {} + } + + @property + def ipmitool_args(self): + """ + """ + return ["cxoem", "fw", "status", self._params['tftp_handle']] + + +class FWCheckCommand(CommandWithErrors): + """Describes the cxoem fw check IPMI command + + """ + + name = "Perform CRC of a Firmware Image" + result_type = FWCheckResult + + response_fields = { + 'Partition' : {}, + 'Slot' : {'attr': 'partition'}, + 'CRC32' : {}, + 'Error' : {} + } + + @property + def ipmitool_args(self): + """ + """ + return ["cxoem", "fw", "check", self._params['partition']] + + +class FWCancelCommand(CommandWithErrors): + """Describes the cxoem fw cancel IPMI command + + """ + + name = "Cancel an In-Progress Upload or Download" + result_type = FWCancelResult + + response_fields = { + "" : {} + } + + @property + def ipmitool_args(self): + """ + """ + return ["cxoem", "fw", "cancel", self._params['job_id']] + + +class FWInfoCommand(CommandWithErrors): + """Describes the cxoem fw info IPMI command + + """ + + name = "Request Firmware Information" + result_type = FWInfo + response_parser = ResponseParserMixIn.parse_colon_record_list + + response_fields = { + "Partition" : {}, + "Slot" : {"attr": "partition"}, + "Type" : {}, + "Offset" : {}, + "Size" : {}, + "Priority" : {}, + "Daddr" : {}, + "Flags" : {}, + "In Use" : {}, + "Version" : {}, + "Error" : {} + } + + ipmitool_args = ["cxoem", "fw", "info"] + + +class FWGetCommand(CommandWithErrors): + """Describes the cxoem fw get IPMI command + + """ + + name = "Retrieve Raw Firmware From Device" + result_type = FWGetResult + + response_fields = { + 'File Name' : {}, + 'Address' : {}, + 'Size' : {}, + 'IP' : {}, + 'TFTP Handle ID' : {}, + 'Start raw transfer failed' : {'attr': 'fw_error'} + } + + @property + def ipmitool_args(self): + """ + """ + return ["cxoem", "fw", "get", self._params['filename'], + self._params['offset'], self._params['size'], + "tftp", self._params['tftp_addr']] + + +class FWPutCommand(CommandWithErrors): + """Describes the cxoem fw put IPMI command + + """ + + name = "Update Raw Firmware To Device" + result_type = FWPutResult + + response_fields = { + 'File Name' : {}, + 'Address' : {}, + 'TSize' : {}, + 'IP' : {}, + 'TFTP Handle ID' : {}, + 'Start raw transfer failed' : {'attr': 'fw_error'} + } + + @property + def ipmitool_args(self): + """ + """ + return ["cxoem", "fw", "put", self._params['filename'], + self._params['offset'], self._params['size'], + "tftp", self._params['tftp_addr']] + + +class FWResetCommand(CommandWithErrors): + """Describes the cxoem fw reset IPMI command + + """ + + name = "Reset to factory default" + result_type = FWResetResult + + response_fields = { + "Error" : {} + } + + ipmitool_args = ["cxoem", "fw", "reset"] + + + +class FWVersionCommand(CommandWithErrors): + """Describes the cxoem fw version IPMI command + + """ + + name = "Set the firmware version" + result_type = FWVersionResult + + response_fields = { + "Error" : {} + } + + @property + def ipmitool_args(self): + return ["cxoem", "fw", "version", self._params['version']] + + +fw_commands = { + "fw_download" : FWDownloadCommand, + "fw_upload" : FWUploadCommand, + "fw_register_read" : FWRegisterReadCommand, + "fw_register_write" : FWRegisterWriteCommand, + "fw_activate" : FWActivateCommand, + "fw_invalidate" : FWInvalidateCommand, + "fw_flags" : FWFlagsCommand, + "fw_status" : FWStatusCommand, + "fw_check" : FWCheckCommand, + "fw_cancel" : FWCancelCommand, + "fw_info" : FWInfoCommand, + "fw_get" : FWGetCommand, + "fw_put" : FWPutCommand, + "fw_reset" : FWResetCommand, + "fw_version" : FWVersionCommand +} diff --git a/pyipmi/commands/info.py b/pyipmi/commands/info.py new file mode 100644 index 0000000..650e951 --- /dev/null +++ b/pyipmi/commands/info.py @@ -0,0 +1,92 @@ +# 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. + + +from .. import Command +from pyipmi.info import * +from pyipmi.tools.responseparser import ResponseParserMixIn +from pyipmi import IpmiError + +class InfoBasicCommand(Command, ResponseParserMixIn): + """ Describes the cxoem info basic IPMI command + """ + + name = "Retrieve basic SoC info" + + ipmitool_args = ["cxoem", "info", "basic"] + + def parse_results(self, out, err): + """ Parse ipmitool output + """ + result = InfoBasicResult() + + if out.startswith("Calxeda SoC"): + for line in out.splitlines(): + if line.lstrip().startswith("Calxeda SoC"): + result.iana = int(line.split()[2].strip("()"), 16) + elif line.lstrip().startswith("Firmware Version"): + result.firmware_version = line.partition(":")[2].strip() + elif line.lstrip().startswith("SoC Version"): + result.ecme_version = line.partition(":")[2].strip() + elif line.lstrip().startswith("Build Number"): + result.ecme_build_number = line.partition(":")[2].strip() + elif line.lstrip().startswith("Timestamp"): + result.ecme_timestamp = int(line.split()[1].strip(":()")) + elif err.startswith("Error: "): + raise IpmiError(err.splitlines()[0][7:]) + else: + raise IpmiError("Unknown Error") + + return result + +class InfoCardCommand(Command, ResponseParserMixIn): + """ Describes the cxoem info card IPMI command + """ + + name = "Retrieve card info" + + ipmitool_args = ["cxoem", "info", "card"] + + result_type = InfoCardResult + response_fields = { + 'Board Type' : {'attr' : 'type'}, + 'Board Revision' : {'attr' : 'revision'} + } + + def parse_results(self, out, err): + result = ResponseParserMixIn.parse_results(self, out, err) + if not (hasattr(result, 'type') and hasattr(result, 'revision')): + raise IpmiError(out.strip()) + return result + +info_commands = { + "info_basic" : InfoBasicCommand, + "info_card" : InfoCardCommand +} diff --git a/pyipmi/commands/lan.py b/pyipmi/commands/lan.py new file mode 100644 index 0000000..4316700 --- /dev/null +++ b/pyipmi/commands/lan.py @@ -0,0 +1,127 @@ +# 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. + + +"""lan config related commands""" + +from .. import Command +from pyipmi.lan import * +from pyipmi.tools.responseparser import (ResponseParserMixIn, + str_to_list, + str_to_dict) + + +class LANPrintCommand(Command, ResponseParserMixIn): + """Describes the lan print ipmitool command + """ + name = "LAN Print" + result_type = LANPrintResults + + def parse_response(self, out, err): + """ Strip out extraneous colons to allow more generic parsing + """ + new_out_list = map(lambda x: x.lstrip(' \t\n:'), out.split('\n')) + new_out = reduce(lambda x, y: x + '\n' + y, new_out_list) + + return self.response_parser(new_out, err) + + def first_word_only(line): + y = line.split(' ') + return y[0] + + response_fields = { + 'Set in Progress' : {}, + 'Auth Type Support' : {'parser' : str_to_list}, + 'Auth Type Enable' : {'lines' : 5, + 'parser' : str_to_dict, + 'operator' : ':', + 'delimiter' : '\n', + 'value_parser' : str_to_list}, + 'IP Address Source' : {}, + 'IP Address' : {}, + 'Subnet Mask' : {}, + 'MAC Address' : {}, + 'SNMP Community String' : {}, + 'IP Header' : {'parser' : str_to_dict, + 'operator' : '=', + 'delimiter' : ' '}, + 'BMC ARP Control' : {'parser' : str_to_list, + 'delimiter' : ','}, + 'Gratituous ARP Intrvl' : {'parser' : first_word_only}, + 'Default Gateway IP' : {}, + 'Default Gateway MAC' : {}, + 'TFTP Server IP' : {}, + 'NTP Server IP' : {}, + 'NTP UDP port' : {}, + 'OEM MAC0' : {}, + 'OEM MAC1' : {}, + 'OEM MAC2' : {}, + 'OEM OUID' : {}, + 'Supercluster OUID' : {}, + 'Supercluster mode' : {}, + 'Supercluster FID' : {}, + '802.1q VLAN ID' : {}, + '802.1q VLAN Priority' : {}, + 'RMCP+ Cipher Suites' : {'parser' : str_to_list, + 'delimiter' : ','}, + 'Cipher Suite Priv Max' : {} + } + + @property + def ipmitool_args(self): + channel = self._params.get('channel', '') + return ["lan", "print", channel] + + +class LANSetCommand(Command, ResponseParserMixIn): + """Describes the ipmitool lan set command + """ + name = "LAN Set" + result_type = LANSetResult + + response_fields = { + } + + @property + def ipmitool_args(self): + command = "lan set %s %s" % (self._params['channel'], self._params['command']) + command_array = command.split(' ') + params = self._params['param'] + param_array = [params] + if self._params['command'] == 'auth': + param_array = params.split(' ') + command_array.extend(param_array) + return command_array + + +lan_commands = { + 'lan_print' : LANPrintCommand, + 'lan_set' : LANSetCommand +} diff --git a/pyipmi/commands/mc.py b/pyipmi/commands/mc.py new file mode 100644 index 0000000..b94c23b --- /dev/null +++ b/pyipmi/commands/mc.py @@ -0,0 +1,69 @@ +# 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. + + +from .. import Command +from pyipmi.tools.responseparser import ResponseParserMixIn +from pyipmi.mc import * + +class CommandWithErrors(Command, ResponseParserMixIn): + + def parse_response(self, out, err): + """Parse the response to a command + + The 'ipmitool_response_format' attribute is used to determine + what parser to use to for interpreting the results. + + Arguments: + out -- the text response of an command from stdout + err -- the text response of an command from stderr + """ + + out = out + err + return self.response_parser(out, err) + +class MCResetCommand(CommandWithErrors): + """ Describes the cxoem MC reset IPMI command + """ + + name = "Reset the MC" + result_type = MCResetResult + + response_fields = { + "Error" : {} + } + + @property + def ipmitool_args(self): + return ["mc", "reset", self._params['mode']] + +mc_commands = { + "mc_reset" : MCResetCommand, +} diff --git a/pyipmi/commands/payload.py b/pyipmi/commands/payload.py new file mode 100644 index 0000000..5d8df53 --- /dev/null +++ b/pyipmi/commands/payload.py @@ -0,0 +1,65 @@ +# 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. + + +"""A series of wrappers around RMCP+ Payload commands""" + +from pyipmi import Command, InteractiveCommand, IpmiError +from pyipmi.tools.responseparser import ResponseParserMixIn + + +class ActivatePayloadCommand(InteractiveCommand, ResponseParserMixIn): + """Describes the Activate Payload command""" + + #TODO: there could be other payload types + + name = "Activate Payload" + ipmitool_args = ["-I", "lanplus", "-C", "0", "sol", "activate"] + + +class DeactivatePayloadCommand(Command, ResponseParserMixIn): + """Describes the Deactivate Payload command""" + + #TODO: there could be other payload types + + def handle_command_error(self, out, err): + if err.find('Info: SOL payload already de-activated') > -1: + return + + raise IpmiError(err) + + name = "Deactivate Payload" + ipmitool_args = ["-I", "lanplus", "sol", "deactivate"] + + +payload_commands = { + "activate_payload" : ActivatePayloadCommand, + "deactivate_payload" : DeactivatePayloadCommand +} diff --git a/pyipmi/commands/pef.py b/pyipmi/commands/pef.py new file mode 100644 index 0000000..6221d1a --- /dev/null +++ b/pyipmi/commands/pef.py @@ -0,0 +1,130 @@ +# 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. + + +"""PEF related commands""" + +from .. import Command +from pyipmi.pef import * +from pyipmi.tools.responseparser import ResponseParserMixIn + + +class PEFGetInfoCommand(Command, ResponseParserMixIn): + """Describes the get PEF info IPMI command + + This is "pef info" to ipmitool + """ + name = "Get PEF Capabilities" + result_type = PEFInfoResult + + response_fields = { + 'Version' : {}, + 'PEF table size' : {}, + 'Alert policy table size' : {}, + 'System GUID' : {}, + 'Alert' : {}, + 'Power-off' : {}, + 'Reset' : {}, + 'Power-cycle' : {}, + 'OEM-defined' : {}, + 'Diagnostic-interrupt' : {} + } + + ipmitool_args = ["-v", "pef", "info"] + + +class PEFGetPolicyCommand(Command, ResponseParserMixIn): + """Describes the get PEF policies ipmitool command + + This is "pef policy" to ipmitool + """ + + name = "Get PEF Policy" + result_type = PEFPolicyResult + + response_fields = { + } + + ipmitool_args = ["pef", "policy"] + + +class PEFGetStatusCommand(Command, ResponseParserMixIn): + """Describes the get PEF status ipmitool command + + This is "pef status" to ipmitool + """ + name = "Get PEF Status" + result_type = PEFStatusResult + + response_fields = { + 'Last SEL addition' : {}, + 'Last SEL record ID' : {}, + 'Last S/W processed ID' : {}, + 'Last BMC processed ID' : {}, + 'PEF' : {}, + 'PEF event messages' : {}, + 'PEF startup delay' : {}, + 'Alert startup delay' : {}, + 'Alert' : {}, + 'Power-off' : {}, + 'Reset' : {}, + 'Power-cycle' : {}, + 'OEM-defined' : {}, + 'Diagnostic-interrupt' : {} + } + + ipmitool_args = ["pef", "status"] + + +class PEFListEntriesCommand(Command, ResponseParserMixIn): + """Describes the get PEF list entries ipmitool command + + This is "pef list" to ipmitool + """ + name = "List PEF Entries" + + response_parser = ResponseParserMixIn.parse_colon_record_list + + result_type = PEFListResult + + response_fields = { + 'PEF table entry' : {}, + 'Status' : {} + } + + ipmitool_args = ["-v", "pef", "list"] + + +pef_commands = { + 'pef_get_info' : PEFGetInfoCommand, + 'pef_get_status' : PEFGetStatusCommand, + 'pef_get_policies' : PEFGetPolicyCommand, + 'pef_list_entries' : PEFListEntriesCommand +} diff --git a/pyipmi/commands/pet.py b/pyipmi/commands/pet.py new file mode 100644 index 0000000..178a4e7 --- /dev/null +++ b/pyipmi/commands/pet.py @@ -0,0 +1,55 @@ +# 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. + + +"""PEF related commands""" + +from .. import Command +from pyipmi.pet import * +from pyipmi.tools.responseparser import ResponseParserMixIn + + +class PETAcknowledgeCommand(Command, ResponseParserMixIn): + """Describes the PET Acknowledge command + + This is "--pet-acknowledge" to ipmi-pet + """ + name = "Send a PET Acknowledge" + result_type = PETAcknowledgeResult + + response_fields = { + } + + ipmi_pet_args = ['--pet-acknowledge'] + + +pet_commands = { + 'pet_acknowledge' : PETAcknowledgeCommand +} diff --git a/pyipmi/commands/sdr.py b/pyipmi/commands/sdr.py new file mode 100644 index 0000000..41e8f69 --- /dev/null +++ b/pyipmi/commands/sdr.py @@ -0,0 +1,110 @@ +# 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. + + +"""SDR related commands""" +import re + +from .. import Command +from .. sdr import Sdr, AnalogSdr +from pyipmi.tools.responseparser import ResponseParserMixIn + +class SdrListCommand(Command, ResponseParserMixIn): + """Describes the sdr list command + + This is not a single IPMI request type - it's an ipmitool + command that's composed of multiple IPMI requests. + """ + + name = 'SDR List' + result_type = Sdr + + response_parser = ResponseParserMixIn.parse_colon_record_list + ipmitool_args = ['-v', 'sdr', 'list', 'all'] + + def sensor_name_parser(string): + return string.split('(')[0].strip() + + def entity_id_parser(string): + m = re.search('(\d.\d{1,2})', string) + return m.groups()[0] + + def get_response_types(self, record): + """Only matches Analog sensors right now. + + There are several more types of records to match, if they + are needed. + """ + if re.search('Sensor Type \(Analog\)', record): + return AnalogSdr, self.analog_response_fields + else: + return None, None + + """ + Unparsed fields for analog sensors: + + Readable Thresholds : lnr lcr lnc unc ucr unr + Settable Thresholds : lnr lcr lnc unc ucr unr + Threshold Read Mask : lnr lcr lnc unc ucr unr + Assertion Events : + Assertions Enabled : unc+ ucr+ unr+ + Deassertions Enabled : unc+ ucr+ unr+ + """ + analog_response_fields = { + 'Sensor ID' : { + 'attr' : 'sensor_name', + 'parser' : sensor_name_parser + }, + 'Entity ID' : { + 'attr' : 'entity_id', + 'parser' : entity_id_parser + }, + 'Sensor Type (Analog)' : { 'attr' : 'sensor_type' }, + 'Sensor Reading' : {}, + 'Status' : {}, + 'Nominal Reading' : {}, + 'Normal Minimum' : {}, + 'Normal Maximum' : {}, + 'Upper non-recoverable' : {}, + 'Upper critical' : {}, + 'Upper non-critical' : {}, + 'Lower non-recoverable' : {}, + 'Lower critical' : {}, + 'Lower non-critical' : {}, + 'Positive Hysteresis' : {}, + 'Negative Hysteresis' : {}, + 'Minimum sensor range' : {}, + 'Maximum sensor range' : {}, + 'Event Message Control' : {}, + } + +sdr_commands = { + "get_sdr_list" : SdrListCommand +} 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 +} diff --git a/pyipmi/commands/sol.py b/pyipmi/commands/sol.py new file mode 100644 index 0000000..98fdfd8 --- /dev/null +++ b/pyipmi/commands/sol.py @@ -0,0 +1,207 @@ +# 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. + + +"""A series of wrappers around SOL commands""" + +from pyipmi import Command, IpmiError +from pyipmi.tools.responseparser import ResponseParserMixIn, str2bool + + +def bit_rate_parser(bit_rate): + """Parse a bit rate returned from ipmitool's "sol info" command""" + assert bit_rate in ('IPMI-Over-Serial-Setting', '9.6', '19.2', + '38.4', '57.6', '115.2') + + if bit_rate != 'IPMI-Over-Serial-Setting': + bit_rate = float(bit_rate) + #TODO: maybe find the IPMI-Over-Serial-Setting? + + return bit_rate + +def channel_parser(channel): + """Parse a channel returned from ipmitool's "sol info" command. + Channel format is: "%d (%x)" % (channel, channel) + """ + + chan, xchan = channel.split(' (') + return int(chan) + +def bool2str(boolval): + """Map True to 'true', False to 'false'""" + return str(boolval).lower() + +def priv_level_formatter(level): + """Format privilege level""" + level = level.lower() + if level == "administrator": + level = "admin" + return level + +# need to know four ipmitool-specific things about each configuration parameter +# set_name: name used in ipmitool's "sol set" command +# get_name: name printed from ipmitool's "sol info" command +# parser: a function to parse the value printed by ipmitool's "sol info" command +# formatter: formatter tool-independant values into formats required by tool +IPMITOOL_SOL_PARAMETERS = { + 'set_in_progress': { + 'set_name' : 'set-in-progress', + 'get_name' : 'Set in progress', + 'parser' : lambda s: s.replace('-', '_'), + 'formatter' : lambda s: s.replace('_', '-'), + }, + 'enable' : { + 'set_name' : 'enabled', + 'get_name' : 'Enabled', + 'parser' : str2bool, + 'formatter' : bool2str, + }, + 'force_encryption' : { + 'set_name' : 'force-encryption', + 'get_name' : 'Force Encryption', + 'parser' : str2bool, + 'formatter' : bool2str, + }, + 'force_authentication' : { + 'set_name' : 'force-authentication', + 'get_name' : 'Force Authentication', + 'parser' : str2bool, + 'formatter' : bool2str, + }, + 'privilege_level' : { + 'set_name' : 'privilege-level', + 'get_name' : 'Privilege Level', + 'parser' : str, + 'formatter' : priv_level_formatter, + }, + 'character_accumulate_interval' : { + 'set_name' : 'character-accumulate-level', + 'get_name' : 'Character Accumulate Level (ms)', + 'parser' : lambda s: int(s) / 5, + 'formatter' : str, + }, + 'character_send_threshold' : { + 'set_name' : 'character-send-threshold', + 'get_name' : 'Character Send Threshold', + 'parser' : int, + 'formatter' : str, + }, + 'retry_count' : { + 'set_name' : 'retry-count', + 'get_name' : 'Retry Count', + 'parser' : int, + 'formatter' : str, + }, + 'retry_interval' : { + 'set_name' : 'retry-interval', + 'get_name' : 'Retry Interval (ms)', + 'parser' : lambda s: int(s) / 10, + 'formatter' : str, + }, + 'volatile_bit_rate' : { + 'set_name' : 'volatile-bit-rate', + 'get_name' : 'Volatile Bit Rate (kbps)', + 'parser' : bit_rate_parser, + 'formatter' : str, + }, + 'non_volatile_bit_rate' : { + 'set_name' : 'non-volatile-bit-rate', + 'get_name' : 'Non-Volatile Bit Rate (kbps)', + 'parser' : bit_rate_parser, + 'formatter' : str, + }, + 'payload_channel' : { + 'set_name' : None, + 'get_name' : 'Payload Channel', + 'parser' : channel_parser, + 'formatter' : None, + }, + 'payload_port_number' : { + 'set_name' : None, + 'get_name' : 'Payload Port', + 'parser' : int, + 'formatter' : None, + } +} + +# TODO: why does atom only work with lanplus, but qemu works on the lan iface? +# TODO: enable/disable encryption +IPMITOOL_SOL_ARGS = ["-I", "lanplus", "-C", "0", "sol"] + +class SetSOLConfigurationParametersCommand(Command, ResponseParserMixIn): + """Describes the Set SOL Configuration Parameters command""" + + # ipmitool handles setting set-in-progress/set-complete for us + # however, other tools might not. this is where that'd be handled + + name = "Set SOL Configuration Parameters" + + @property + def ipmitool_args(self): + param = self._params['param'] + ipmitool_param = IPMITOOL_SOL_PARAMETERS[param]['set_name'] + formatter = IPMITOOL_SOL_PARAMETERS[param]['formatter'] + val = formatter(self._params['value']) + + if param is None: + raise IpmiError('ipmitool does not support "sol set %s" ' % param) + + return IPMITOOL_SOL_ARGS + ["set", ipmitool_param, val, 'noguard'] + + +class GetSOLConfigurationParametersCommand(Command, ResponseParserMixIn): + """Describes the Get SOL Configuration Parameters command""" + + name = "Get SOL Configuration Parameters" + ipmitool_args = IPMITOOL_SOL_ARGS + ["info"] + + def parse_results(self, response, err): + """Parse the output from "sol info" for the desired parameters, + format the result, and return it. + """ + response = response.split('\n') + result = {} + + params = self._params['params'] + for param in params: + field = IPMITOOL_SOL_PARAMETERS[param]['get_name'] + parse = IPMITOOL_SOL_PARAMETERS[param]['parser'] + + field_value, = filter(lambda s: s.find(field) == 0, response) + field, value = field_value.split(': ') + result[param] = parse(value) + + return result + + +sol_commands = { + "set_sol_config_params" : SetSOLConfigurationParametersCommand, + "get_sol_config_params" : GetSOLConfigurationParametersCommand +} diff --git a/pyipmi/commands/user.py b/pyipmi/commands/user.py new file mode 100644 index 0000000..6ecdbe1 --- /dev/null +++ b/pyipmi/commands/user.py @@ -0,0 +1,163 @@ +# 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. + + +"""user management IPMI commands""" + +from .. import Command +from pyipmi.user import * +from pyipmi.tools.responseparser import (ResponseParserMixIn, + str_to_list, + str_to_dict) + + +class UserListCommand(Command, ResponseParserMixIn): + """Describes the user list ipmitool command + """ + name = "User List" + result_type = UserListResults + + def parse_response(self, out, err): + """ Output is a table with a header row: + ID Name Callin Link Auth IPMI Msg Channel Priv Limit + 1 anonymous true false false NO ACCESS + """ + result = {} + for line in out.strip().split('\n')[1:]: + user_info = self.result_type() + + user_info_list = line.strip().split() + if len(user_info_list) < 5: + continue + + key = line[0:3].strip() + user_info.name = line[4:20].strip() + user_info.callin = line[22:28].strip() + user_info.link_auth = line[29:39].strip() + user_info.ipmi_msg = line[40:48].strip() + user_info.channel_priv_limit = line[51:].strip() + + result[key] = user_info + + return result + + @property + def ipmitool_args(self): + channel = self._params.get('channel', '') + return ["user", "list", channel] + + +class UserSetNameCommand(Command, ResponseParserMixIn): + """Describes the user set name ipmitool command + """ + name = "User Set Name" + result_type = UserSetNameResults + + response_fields = { + 'Field Name' : {} + } + + @property + def ipmitool_args(self): + return ["user", "set", "name", self._params['userid'], + self._params['name']] + + +class UserSetPasswordCommand(Command, ResponseParserMixIn): + """Describes the user set password ipmitool command + """ + name = "User Set Password" + result_type = UserSetPasswordResults + + response_fields = { + 'Field Name' : {} + } + + @property + def ipmitool_args(self): + password = self._params.get('password', '') + return ["user", "set", "password", self._params['userid'], password] + + +class UserDisableCommand(Command, ResponseParserMixIn): + """Describes the user disable ipmitool command + """ + name = "User Disable" + result_type = UserDisableResults + + response_fields = { + 'Field Name' : {} + } + + @property + def ipmitool_args(self): + return ["user", "disable", self._params['userid']] + + +class UserEnableCommand(Command, ResponseParserMixIn): + """Describes the user enable ipmitool command + """ + name = "User Enable" + result_type = UserEnableResults + + response_fields = { + 'Field Name' : {} + } + + @property + def ipmitool_args(self): + return ["user", "enable", self._params['userid']] + + +class UserPrivCommand(Command, ResponseParserMixIn): + """Describes the user priv ipmitool command + """ + name = "User Set Privileges" + result_type = UserPrivResults + + response_fields = { + 'Field Name' : {} + } + + @property + def ipmitool_args(self): + channel = self._params.get('channel', '') + return ["user", "priv", self._params['userid'], + self._params['priv_level'], channel] + + +user_commands = { + 'user_list' : UserListCommand, + 'user_set_name' : UserSetNameCommand, + 'user_set_password' : UserSetPasswordCommand, + 'user_enable' : UserEnableCommand, + 'user_disable' : UserDisableCommand, + 'user_priv' : UserPrivCommand +} diff --git a/pyipmi/commands/watchdog.py b/pyipmi/commands/watchdog.py new file mode 100644 index 0000000..1f3c5c0 --- /dev/null +++ b/pyipmi/commands/watchdog.py @@ -0,0 +1,92 @@ +# 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. + + +"""watchdog related commands""" + +from .. import Command +from pyipmi.watchdog import * +from pyipmi.tools.responseparser import ResponseParserMixIn + + +class WatchdogGetCommand(Command, ResponseParserMixIn): + """Describes the watchdog get IPMI command + + This is "mc watchdog get" to ipmitool + """ + name = "Watchdog Get" + result_type = WatchdogGetResult + + response_fields = { + 'Watchdog Timer Use' : {}, + 'Watchdog Timer Is' : {}, + 'Watchdog Timer Actions' : {}, + 'Pre-timeout interval' : {}, + 'Timer Expiration Flags' : {}, + 'Initial Countdown' : {}, + 'Present Countdown' : {} + } + + ipmitool_args = ["mc", "watchdog", "get"] + + +class WatchdogResetCommand(Command, ResponseParserMixIn): + """Describes the watchdog rest IPMI command + + This is "mc watchdog reset" to ipmitool + """ + name = "Watchdog Reset" + result_type = WatchdogResetResult + + response_fields = { + } + + ipmitool_args = ["mc", "watchdog", "reset"] + + +class WatchdogOffCommand(Command, ResponseParserMixIn): + """Describes the watchdog off IPMI command + + This is "mc watchdog off" to ipmitool + """ + name = "Watchdog Off" + result_type = WatchdogOffResult + + response_fields = { + } + + ipmitool_args = ["mc", "watchdog", "off"] + + +watchdog_commands = { + 'watchdog_get' : WatchdogGetCommand, + 'watchdog_reset' : WatchdogResetCommand, + 'watchdog_off' : WatchdogOffCommand +} |