纯pythonbastedipmi客户端由Hyve Design Solutions开发。
hyve-pyipmi的Python项目详细描述
Hyve Pyimpi公司
由Hyve Design Solutions开发的基于Python的IPMI客户端。在
这个包的最初目的是提供一个纯基于python的IPMI客户端库,用于为IPMI服务开发python测试脚本。它提供了两类:一类是用于IPMI raw命令的,另一类是用于PyIPMI命令的,这类命令类似于著名的ipmitool命令,如“ipmitool mc info”或“ipmitool sdr list”。在
通过这个纯Python库,为BMC开发人员提供了一些控制台程序。在
包中包含示例以演示如何编写测试脚本。使用这个纯Python库的性能比使用shell脚本+对ipmitool的系统调用的混合方法来开发测试脚本要快得多。在
特点
- 支持的IPMI通道
- RMCP
- RMCP+
- 从LAN到IPMB的消息桥接
- 控制台程序
- pyipmi-一个类似ipmitool的Python程序
- pyipmr—Python程序支持“ipmitool raw”,并具有消息桥接功能
- pyping-RMCP客户端
- pysh-PyIPMI命令的交互式shell,具有自动完成和上/下键来显示以前的命令
- 自动测试界面
- IPMI原始命令支持(见下面的示例1-3)
- PyIPMI命令支持(见下面的示例4-6)
安装
以下步骤在ubuntudesktop 16.04 LTS、18.04 LTS和20.04 LTS上进行了测试。在
1) 先决条件
$ sudo apt -y install git python3-pip
2) 下载源代码
^{pr2}$3) 安装Hyve PyIPMI包和控制台程序
$ pip3 install .
测试Hyve PyIPMI
默认情况下,pip3将在$HOME/.local/lib/python3.x/site-packages中安装Hyve-PyIPMI包,并在$HOME/.local/bin中安装其控制台程序。一般来说,站点包目录已经包含在系统路径您需要自己在PATH中添加bin目录。例如,执行
$ export PATH=~/.local/bin:$PATH
然后,您就可以执行第一个PyIPMI命令。例如,我们执行与ipmitool非常相似的内容,如下所示:
$ pyipmi -H 192.168.0.169 -I lanplus -U root -P root123 raw 6 1
在第一次使用包时,它会自动在$HOME/.config/pyipmi中生成一个用户配置文件/pyipmi.conf默认设置。然后,支持的选项将覆盖某些设置。在上面的示例中,它指定了四个选项并发出一个原始IPMI命令。在
创建配置文件后,您可以选择使用配置文件中的所有设置,也可以像前面的示例一样继续覆盖某些选项。程序将自动在配置文件中记录最新的覆盖值。在
$ pyipmi sdr list # Just use the settings in the config file
$ pyipmi -C 2 user list # Use RMCP+ Cipher Suite 2
$ pyipmi -U hyve -P hyve456 lan print 1 # User credential hyve/hyve456
键入-h以显示所有命令选项,并使用“help”命令列出可用命令。在
$ pyipmi -h
$ pyipmi help
高级用法
程序pyipmr等于“pyipmi raw”+附加功能。它支持
- IPMI响应LUN不是0
- 从局域网到IPMB的IPMI消息桥接
$ pyipmr 6 1 # Get Device ID (NetFn=App, CMD=01h)
$ pyipmr -L 1 6 1 # LUN = 1
$ pyipmr -b 6 -t 0x2c raw 6 1 # Bridge Get Device ID to destination 0x2c via channel 6
测试脚本示例
Sample 1
#!/usr/bin/env python3
import sys
from pyipmi.util import PyTest
# Just overwrite the run_commands() method and you can issue
# IPMI commands like this example
class Sample1(PyTest):
def __init__(self):
super(Sample1, self).__init__()
def run_commands(self, argv=None):
# issue_raw_cmd(req, lun):
# req (list): [NetFn, CMD, Req_Data]
# lun (int): default is 0
print('Get Device ID:')
rsp = self.intf.issue_raw_cmd([6, 1])
self.print_rsp(rsp)
print('\nGet User Name 2:')
rsp = self.intf.issue_raw_cmd([6, 0x46, 2])
self.print_rsp(rsp)
print('\nGet LAN Config 1:')
rsp = self.intf.issue_raw_cmd([0x0c, 2, 1, 1, 0, 0])
self.print_rsp(rsp)
if __name__ == '__main__':
test = Sample1()
sys.exit(test.run())
Sample 2
#!/usr/bin/env python3
import sys
from pyipmi.util import PyTest
from pyipmi.util.config import PyOpts
# Same as sample1, with simple checks on the response data
# and overwrite some values of the user config
class Sample2(PyTest):
def __init__(self, opts):
super(Sample2, self).__init__(opts)
def run_commands(self, argv=None):
req = ([[6, 1], # Get Device ID
[6, 0x46, 2], # Get User Name 2
[0x0c, 2, 1, 1, 0, 0]]) # Get LAN Config 1
rsp = ([[0, 0x22, 1, 1, 2, 2, 0x9f, 0x55, 0xda, 0, 1, 0, 0x59, 1, 0, 0],
[0, 0x72, 0x6f, 0x6f, 0x74, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0x11, 0x15]])
# run the commands
count_p = 0
count_f = 0
for i in range(len(req)):
rsp_one = self.intf.issue_raw_cmd(req[i])
if rsp_one == rsp[i]:
print('test case {0}: PASSED!'.format(i + 1))
count_p += 1
else:
print('test case {0}: FAILED!'.format(i + 1))
count_f += 1
# output the results
print('Total {0} cases executed: PASSED {1}, FAILED {2}.'
.format(count_p + count_f, count_p, count_f))
if __name__ == '__main__':
pyopts = PyOpts()
pyopts.add_options()
opts = pyopts.parse_options('-U hyve -P hyve123')
test = Sample2(opts)
sys.exit(test.run())
Sample 3
#!/usr/bin/env python3
import sys
from pyipmi.util import PyTest
from pyipmi.util.config import PyOpts
# Message bridging example
# Support the following configuration
# [PyIPMI] <-- LAN (RMCP/RMCP+) --> [BMC] <-- IPMB --> [ME]
class Sample3(PyTest):
def __init__(self, opts, chnl, target):
self.chnl = chnl
self.target = target
super(Sample3, self).__init__(opts)
def bridge_cmd(self, req):
# issue_bridging_cmd(chnl, target, req, lun):
# chnl (int): IPMI channel number to bridge the message
# target (int): I2C slave address of the bridging destination
# req (list): [NetFn, CMD, Req_Data]
# lun (int): default is 0
return self.intf.issue_bridging_cmd(self.chnl, self.target, req)
def run_commands(self, argv=None):
print('Get Device ID:')
rsp = self.bridge_cmd([6, 1])
self.print_rsp(rsp)
print('\nGet SEL Time:')
rsp = self.bridge_cmd([0xa, 0x48])
self.print_rsp(rsp)
print('\nGet Event Receiver:')
rsp = self.bridge_cmd([4, 1])
self.print_rsp(rsp)
print('\nGet Intel ME FW Capabilities:')
rsp = self.bridge_cmd([0x2e, 0xde, 0x57, 1, 0, 0, 0, 0, 0, 2, 0xff, 0])
self.print_rsp(rsp)
print('\nGet Intel ME Factory Presets Signature:')
rsp = self.bridge_cmd([0x2e, 0xe0, 0x57, 1, 0])
self.print_rsp(rsp)
print('\nGet Exception Data:')
rsp = self.bridge_cmd([0x2e, 0xe6, 0x57, 1, 0, 0])
self.print_rsp(rsp)
print('\nGet Sensor Reading:')
sensor_num = (8, 197)
for num in sensor_num:
rsp = self.bridge_cmd([4, 0x2d, num])
self.print_rsp(rsp)
print('\nGet SEL Entry:')
req = [0xa, 0x43, 0, 0, 0, 0, 0, 0xff]
rsp = self.bridge_cmd(req)
id1, id2 = rsp[1:3]
while not (id1 == 0xff and id2 == 0xff):
req[4], req[5] = id1, id2
rsp = self.bridge_cmd(req)
id1, id2 = rsp[1:3]
self.print_rsp(rsp)
if __name__ == '__main__':
pyopts = PyOpts()
pyopts.add_options()
opts = pyopts.parse_options('-H 10.19.84.90 -I lanplus -U admin -P admin')
test = Sample3(opts, 6, 0x2c)
sys.exit(test.run())
Sample 4
#!/usr/bin/env python3
from pyipmi.cmds import PyCmds
if __name__ == '__main__':
# This example shows how to use PyIPMI commands in a script
cmd = PyCmds()
cmd.exec_command('raw 6 1')
cmd.exec_command('mc info')
cmd.exec_command('chassis status')
cmd.exec_command('power status')
cmd.exec_command('sdr list')
cmd.exec_command('sel list')
cmd.exec_command('sensor list')
cmd.exec_command('lan print 1')
cmd.exec_command('user list')
sample 5
#!/usr/bin/env python3
from pyipmi.cmds import PyCmds
from pyipmi.util.config import PyOpts
if __name__ == '__main__':
# Same as sample4,
# with overwriting some of the options in the user config
pyopts = PyOpts()
pyopts.add_options()
opts = pyopts.parse_options('-U hyve -P hyve123')
cmd = PyCmds(opts)
cmd.exec_command('raw 6 1')
cmd.exec_command('mc info')
cmd.exec_command('chassis status')
cmd.exec_command('power status')
cmd.exec_command('sdr list')
cmd.exec_command('sel list')
cmd.exec_command('sensor list')
cmd.exec_command('lan print 1')
cmd.exec_command('user list')
Sample 6
#!/usr/bin/env python3
from pyipmi.cmds import PyCmds, StrEx
from pyipmi.util.config import PyOpts
def find_line(target, src_str):
ret = '(not found)'
list1 = src_str.split('\n')
for s in list1:
if s[:len(target)] == target:
ret = s
break
return ret + '\n'
if __name__ == '__main__':
pyopts = PyOpts()
pyopts.add_options()
opts = pyopts.parse_options('-U hyve -P hyve123')
# Instead of printing out the results to the console, this sample shows
# how to record them in a string named 'print_str'.
print_str = StrEx()
cmd = PyCmds(opts, print_str)
# The results will be appended in 'print_str' when the next command is called,
# just like what you see from the console by running sample4 and sample5.
# If you don't want this, you need to explictly call 'print_str.reset()'
# before calling the next cmd.exec_command().
# In this example, assume we'd like to retrieve specific lines from the outputs
cmd.exec_command('raw 6 1')
ret_all = print_str.get_str()
print_str.reset()
cmd.exec_command('mc info')
ret = print_str.get_str()
ret_all += find_line('Manufacturer ID', ret)
print_str.reset()
cmd.exec_command('lan print 1')
ret = print_str.get_str()
ret_all += find_line('RMCP+ Cipher Suites', ret)
print(ret_all)
联系人
如果您有任何问题或建议,您可以联系Janny Au,这个程序的主要开发人员。在
- 项目
标签: