Skip to main content

Hyve PyIPMI

Pure Python-based IPMI client developed by Hyve Design Solutions.

The original purpose of this package is to provide a pure python-based IPMI client library for developing Python test scripts for the IPMI service. It provides two categories: one is for IPMI raw commands and the other is for PyIPMI commands, which are similar to the famous ipmitool commands like "ipmitool mc info" or "ipmitool sdr list".

By this pure Python library, several console programs are provided for BMC developers' convenience.

Samples are included in the package to show how to write test scripts. The performance of using this pure Python library is significantly faster than using a hybrid method of shell scripts + system calls to ipmitool to develop your test scripts.

Features

  • Supported IPMI channels
    • RMCP
    • RMCP+
    • KCS
    • Message bridging from LAN/KCS to IPMB
  • Console programs
    • pyipmi - a Python program similar to ipmitool
    • pyipmr - a Python program supports "ipmitool raw" and has message bridging capability
    • pyping - an RMCP client
    • pysh - an interactive shell for the PyIPMI commands, with auto completion and up/down keys to show previous commands
  • Auto test interface
    • IPMI raw command support (see samples 1-3 below)
    • PyIPMI command support (see samples 4-6 below)

Installation

The following steps were tested on Ubuntu desktop 16.04 LTS, 18.04 LTS, and 20.04 LTS.

1) Prerequisite

$ sudo apt -y install git python3-pip

2) Download the source

$ git clone https://github.com/hyvedesignsolutions/hyve-pyipmi
$ cd hyve-pyipmi

3) Install the Hyve PyIPMI package and the console programs

$ pip3 install .

Test Hyve PyIPMI

By default, pip3 will install the Hyve PyIPMI package in $HOME/.local/lib/python3.x/site-packages and its console programs in $HOME/.local/bin. Generally speaking, the site-packages directory has been included in sys.path and you need to add the bin directory in PATH by yourself. For example, execute

$ export PATH=~/.local/bin:$PATH

Then, you are able to execute your first PyIPMI command. For example, we execute something very similar to ipmitool as follows:

$ pyipmi -H 192.168.0.169 -I lanplus -U root -P root123 raw 6 1

Note that by default, if you choose to use "-I kcs" that goes through the Linux OpenIPMI driver, you will need root privilege to execute the program.

During the first time when the package is used, it automatically generates a user config file in $HOME/.config/pyipmi/pyipmi.conf with default settings. Then, the options supported will overwrite some of the settings. In the above example, it specifies four options and issues a raw IPMI command.

After the config file is created, you can choose to either use all the settings in the config file or continue to overwrite some of the options as the previous example. The program will automatically record the latest overwritten values in the config file.

$ 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

Type -h to show all the command options and use "help" command to list the available commands.

$ pyipmi -h
$ pyipmi help

Advanced Usage

The program pyipmr is equal to "pyipmi raw" + additional features. It supports

  • IPMI response LUN other than 0
  • IPMI message bridging from LAN to IPMB
$ 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

Test scripts examples

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)

Contact

You may like to contact Janny Au, the main developer of this program, if you have any questions or suggestions.

Metadata

Release files for hyve-pyipmi 1.2.5

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for hyve-pyipmi 1.2.5
File Size Uploaded
hyve-pyipmi-1.2.5.tar.gz 57.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for hyve-pyipmi 1.2.5
File Interpreter ABI Platform
hyve_pyipmi-1.2.5-py3-none-any.whl Python 3 none any Details

Total release size: 156.8 kB

Release files / hyve-pyipmi-1.2.5.tar.gz

Download URL hyve-pyipmi-1.2.5.tar.gz
Size 57.1 kB
Tags Source
SHA-256 checksum
How to use checksums
03a7c28af7694b85eaf23355de17c929f48bff884d617ba73e2d37e5091bef3e
BLAKE2b-256 checksum
How to use checksums
69aa9779df61ac4724de554052c9db45af403baee9be18de91bd3d5f8aa8974b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.4.1 importlib_metadata/4.6.0 pkginfo/1.7.0 requests/2.25.1 requests-toolbelt/0.9.1 tqdm/4.61.1 CPython/3.6.9

Release files / hyve_pyipmi-1.2.5-py3-none-any.whl

Download URL hyve_pyipmi-1.2.5-py3-none-any.whl
Size 99.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
60959d67e8af6b831fae97be595e8303454e9f3f0d110eea138f4208bc310022
BLAKE2b-256 checksum
How to use checksums
dfe8962e2fd4539489125fc73eec8788de6284cff2fcba286d94035906efbd9c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.4.1 importlib_metadata/4.6.0 pkginfo/1.7.0 requests/2.25.1 requests-toolbelt/0.9.1 tqdm/4.61.1 CPython/3.6.9

Release history Release notifications | RSS feed

This release

1.2.5 This release

2 release files

1.2.4

2 release files

1.2.1

2 release files

1.2.0

2 release files

1.1.2

2 release files

1.0.1

2 release files

1.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page