Rubyipmi
A Ruby library for controlling and querying BMC (Baseboard Management Controller) devices. Rubyipmi wraps the freeipmi and ipmitool command-line tools behind a consistent, object-oriented API so you can drive IPMI from Ruby scripts, monitoring tools, or automation without shelling out or parsing CLI output yourself.
Table of Contents
- Requirements
- Installation
- Quick Start
- Usage Scenarios
- Development
- Troubleshooting
- Security
- Projects using Rubyipmi
- Support
- Contributing
- License
- FreeIPMI workarounds
Requirements
- Ruby 3.0+
- One of:
- freeipmi (from source or package), or
- ipmitool
Rubyipmi auto-detects which provider is installed. You can also force a specific provider (see Connection options).
Installation
Add to your Gemfile:
gem 'rubyipmi'
Then:
bundle install
Or install globally:
gem install rubyipmi
Quick Start
require 'rubyipmi'
# Connect (provider is auto-detected: freeipmi or ipmitool)
conn = Rubyipmi.connect("username", "password", "hostname")
# Verify connectivity
conn.connection_works? # => true/false
# Power
conn.chassis.power.on?
conn.chassis.power.off
conn.chassis.power.on
conn.chassis.power.cycle
# Sensors
conn.sensors.names
conn.sensors.list
# FRU (serial, model, etc.)
conn.fru.list
conn.fru.serial
conn.fru.manufacturer
conn.fru.product
# BMC info
conn.bmc.info
conn.bmc.version
Usage Scenarios
Connection options
Basic connection (auto-detect provider):
conn = Rubyipmi.connect("username", "password", "192.168.1.10")
Choose provider explicitly ('auto', 'freeipmi', or 'ipmitool'):
conn = Rubyipmi.connect("username", "password", "192.168.1.10", "freeipmi")
Extra options (privilege, driver):
conn = Rubyipmi.connect("username", "password", "192.168.1.10", "freeipmi", {
privilege: 'ADMINISTRATOR',
driver: 'lan20' # or 'lan15', 'auto', 'open'
})
Local host with OpenIPMI (no credentials; run on the same host as the BMC):
# Uses openipmi driver; no username/password/host needed
conn = Rubyipmi.connect(nil, nil, "localhost", "freeipmi", { driver: 'open' })
Valid privilege values: 'CALLBACK', 'USER', 'OPERATOR', 'ADMINISTRATOR'.
Valid driver values: 'auto', 'lan15', 'lan20', 'open'.
Power control
conn = Rubyipmi.connect(user, pass, host)
conn.chassis.power.on # power on
conn.chassis.power.off # power off
conn.chassis.power.cycle # power cycle
conn.chassis.power.on? # => true if on
conn.chassis.power.off? # => true if off
Boot device and PXE
Set next boot device and optionally reboot. Methods take (reboot, persistent):
conn = Rubyipmi.connect(user, pass, host)
# PXE once, then revert to normal boot (reboot now)
conn.chassis.bootpxe(true, false)
# PXE on next reboot only (no reboot now)
conn.chassis.bootpxe(false, false)
# Boot from disk once, with immediate reboot
conn.chassis.bootdisk(true, false)
# Boot from disk from now on (persistent)
conn.chassis.bootdisk(true, true)
# CDROM
conn.chassis.bootcdrom(true, false)
reboot: perform a power cycle after setting the boot device.
persistent: keep the boot device across reboots (otherwise one-time).
Sensors and monitoring
Useful for monitoring stacks (e.g. Sensu, Prometheus exporters):
conn = Rubyipmi.connect(user, pass, host)
# List sensor names
conn.sensors.names
# Full sensor list (array of sensor data)
conn.sensors.list
# Access a sensor by normalized name (underscores, no spaces/dots)
conn.sensors.temperature_cpu1
conn.sensors.fan_speed_1
Example: collect temperatures for a custom monitor:
conn.sensors.list.each do |sensor|
next unless sensor[:name].to_s.include?('temp')
puts "#{sensor[:name]}: #{sensor[:value]} #{sensor[:unit]}"
end
FRU (Field Replaceable Unit) info
Serial numbers, product names, manufacturers:
conn = Rubyipmi.connect(user, pass, host)
conn.fru.list # full FRU data
conn.fru.serial # serial number(s)
conn.fru.manufacturer # manufacturer
conn.fru.product # product name
Handy for asset tracking or automation that needs to identify hardware.
BMC info and diagnostics
BMC info and version:
conn.bmc.info
conn.bmc.version
Connection check (single place to validate credentials/host):
if conn.connection_works?
# proceed with power, sensors, etc.
else
# handle unreachable or bad credentials
end
Generate a diagnostics file (for bug reports or vendor-specific issues):
require 'rubyipmi'
Rubyipmi.get_diag(user, pass, host)
# Writes: /tmp/rubyipmi_diag_data.txt
# Review for sensitive data (IP/MAC, etc.) before sharing.
With debug logging:
require 'rubyipmi'
require 'logger'
Rubyipmi.log_level = Logger::DEBUG
Rubyipmi.get_diag(user, pass, host)
# Also creates /tmp/rubyipmi.log with commands run
Development
Running tests
Unit tests (no BMC required; mocks only):
bundle install
bundle exec rake unit
Integration tests (require a real BMC; they will power off/cycle the device):
Do not run on production systems.
bundle exec rake integration \
ipmiuser=USER \
ipmipass=PASS \
ipmihost=192.168.1.10 \
ipmiprovider=freeipmi
Vagrant-based integration (if you use the spec Vagrant setup):
cd spec && vagrant up && vagrant provision
vagrant ssh -c "/rubyipmi/rake integration ipmiuser=... ipmipass=... ipmihost=... ipmiprovider=freeipmi"
CI: The repo uses GitHub Actions; see .github/workflows/test.yml. Typical flow: checkout → Ruby 3.x → bundle install → bundle exec rake unit → gem build.
Extending the library
Rubyipmi runs the underlying CLI tools via a small command layer. To add or wrap new behavior:
Subclass the provider’s BaseCommand
UseRubyipmi::Freeipmi::Commands::BaseCommandorRubyipmi::Ipmitool::Commands::BaseCommand.Initialize with the executable name (e.g. freeipmi’s
bmc-infooripmitool):
def initialize(opts = {})
= opts
super("bmc-info", opts) # or "ipmitool" for ipmitool
end
Use the shared execution helpers
runcmd– run with currentoptions(e.g. hostname, username, password).runcmd(["--option"])– run with extra arguments.runcmd_with_args([...])– run with only the given args.@resultholds stdout; the return value ofruncmdis the command success (true/false).
Options hash
Connection options (host, user, password, driver, privilege) are inoptions. Add command-specific keys for that run, then delete them after so they don’t leak into the next command:
def some_action
["chassis-identify"] = "FORCE"
runcmd
.delete("chassis-identify")
end
- Expose the new command from the Connection
Inlib/rubyipmi/freeipmi/connection.rb(or ipmitool equivalent), add an accessor and instantiate your command class with@options.
Freeipmi uses many separate binaries (e.g. ipmi-chassis, ipmi-sensors, bmc-info). Ipmitool uses a single ipmitool binary with subcommands. Implement the appropriate BaseCommand and wire it into the connection object.
Troubleshooting
Logging
By default, logging is disabled. To trace commands and options:
require 'rubyipmi'
require 'logger'
Rubyipmi.log_level = Logger::DEBUG
# Log file: /tmp/rubyipmi.log
Custom logger:
custom = Logger.new('/var/log/rubyipmi.log')
custom.progname = 'Rubyipmi'
custom.level = Logger::DEBUG
Rubyipmi.logger = custom
Diagnostics
For support or bug reports, generate a diagnostics file and (after redacting) attach it:
Rubyipmi.get_diag(user, pass, host)
# Edit /tmp/rubyipmi_diag_data.txt to remove sensitive data, then share.
Connection test
conn = Rubyipmi.connect(user, pass, host)
conn.connection_works? # => true/false
Security
Credentials are not passed on the command line. The library uses temporary files (mode 0600) to pass passwords to the underlying CLI tools; files are created and removed around each call. Filenames and directory names are randomized to avoid guessing. Passwords do not appear in process listings or in logs.
Projects using Rubyipmi
- sensu-plugins-ipmi – IPMI checks for Sensu
- smart-proxy – Foreman Smart Proxy (exposes Rubyipmi as a remote API)
- ipmispec
If you use Rubyipmi in a project, open a PR to add it to this list.
Support
- Community: Open a GitHub issue for bugs or feature requests.
- Paid support: LogicMinds offers professional support and custom development.
Test coverage is limited to the hardware available to the maintainers (e.g. HP DL380 G5). IPMI is vendor-neutral, but implementations vary. Devices not regularly tested include Dell, IBM, HP iLO3+, Supermicro, Cisco. If you hit vendor-specific issues, diagnostics (see above) and FreeIPMI workarounds (below) often help.
Contributing
- Check existing issues and PRs to avoid duplicate work.
- Fork the repo and create a feature or bugfix branch.
- Add tests for new behavior (unit tests for logic, integration only when needed).
- Keep Rakefile, version, and history changes minimal; if necessary, isolate in a single commit.
- Open a pull request with a clear description of the change.
License
Copyright (c) 2015 Corey Osman. See LICENSE.txt for details (LGPL-2.1).
FreeIPMI documented workarounds
Many vendors implement IPMI with quirks. FreeIPMI documents workarounds (e.g. -W intel20, -W supermicro20). Rubyipmi may expose or use some of these; for the full list and -W options, see the FreeIPMI documentation. If you need a workaround not yet supported, opening an issue with your BMC model and the FreeIPMI workaround that works on the CLI can help.
Common workaround flags (refer to FreeIPMI for current details):
- assumeio – inband I/O (e.g. HP ProLiant DL145 G1).
- authcap – skip early auth capability checks (e.g. Asus, Intel, Sun).
- intel20 – Intel IPMI 2.0 auth (e.g. Intel SE7520AF2).
- supermicro20 – Supermicro IPMI 2.0 (e.g. H8QME).
- sun20 / opensesspriv – Sun/ILOM auth and session handling.
- idzero, unexpectedauth, forcepermsg, endianseq – session and auth quirks on various Dell, IBM, Tyan, Sun.
- No IPMI 1.5 support – use driver
lan20(e.g. HP ProLiant DL145). - slowcommit / veryslowcommit – BMCs that need slower config commits (e.g. Supermicro, Quanta/Dell).
Hardware listed is where issues were first seen; newer firmware may fix them. Similar or licensed firmware from other vendors may behave the same. To request new workarounds in FreeIPMI, contact freeipmi-users or freeipmi-devel.