5.3 KiB
+++ class = "post" date = "2017-02-10T01:35:38-05:00" tags = [] title = "Build A Raspberry Pi BMC" type = "post" weight = 1 draft = true
+++
IPMI BMCs are pretty ubiquitous in the datacenter and enterprise computing, because in a warehouse full of computers, finding and walking up to one just to reset it or check its console is quite daunting. The same goes for a home server: it may just be in my basement, but in a closed-up rack it becomes a huge hassle to manage a machine without IPMI. I try to get it on every motherboard I buy, but currently my Ceph nodes are running with motherboards that lack built-in IPMI. To make them fully-remote-manageable, I decided they needed a BMC.
Enter the Raspberry Pi
If you don't know what it is, the Rapberry Pi is a small single-board computer, featuring an ARM SOC, Ethernet, USB, video, audio, and most importantly, GPIO, powered by MicroUSB and running the Debian distribution 'Raspbian'. The GPIO pins allow, with a simple utility or Python library, one to controll or read information from various devices. The GPIO header also features a serial port which must be manually enabled.
These features make the Raspberry Pi a perfect fit for a BMC. Low-power usage and an external USB power source means it can be kept on irrespective of the host state. The GPIOs allow on to control a power switch, reset switch, read from the power LED, and generally do a basic suite of server management tasks. And finally the built-in serial connected to a motherboard COM header allows a remote console. The perfect little BMC.
The hardware
Write stuff
The software
Most traditional BMCs are managed via a (terrible) Web UI, which is often prone to breakage or other failures. And often these BMCs are incredibly complex, featuring dozens of menus and gigantic Flash monstrosities just to view their state. By using the Raspberry Pi, a seeming limitation - SSH-only access - becomes a benefit: it becomes trivial to connect to the BMC from a terminal, check the power state or serial console, turn on/off/reset a host, and then disconnect. No crummy web page or point-and-click menu system!
The software side started out as a basic Raspbian system, however I wanted to make it a little more "BMC-like", in a sense stripped-down and easy-to-use with a small set of commands. I started by writing a simple "shell" emulator in BASH, and using a constant loop and hostname prompt along with stty
to keep it focused and running. Each command triggers a function which performs its specific job and then returns to the "shell". While bash
is available also, it should rarely be needed.
The actual software doing the heavy lifting is a combination of screen
, to view the host system serial console, and the gpio
utility by WiringPi (Debian package wiringpi
). The screen
session is configured to start automatically at BMC boot to ensure all serial output is captured and stored for later analysis - a major problem with the (few) SSH-based BMCs I've tried! The gpio
program makes writing and reading the GPIO pins simple and easy, returning 0 or 1 for the low/high states and easily writing states. By writing the BMB shell in bash
, I was able to get all the flexibility I wanted without any programming overhead; the whole thing is under 200 lines.
For example, here is the powersw
function, which manages the power button for the powersw
and kill
commands. By introducing a delay, we can even simulate a power-button force-off event for the kill
task and avoid messing with the raw power:
powersw() {
if [ "$1" == "hard" ]; then
delay=10
echo -n "Holding power switch... "
else
delay=0
echo -n "Pressing power switch... "
fi
gpio mode 1 out
gpio write 1 1
sleep $delay
gpio write 1 0
sleep 1
echo "done."
}
Simply by setting the GPIO high, we simulate a button press, and then by setting the GPIO low, we release the simulated button. The result is a very convincing replica of the standard IPMI/BMC power control functionality. Another feature is to obtain the current system power status (shown multiple times in the image above). This function reads instead of writes the GPIO, in this case the front power LED, and reports the result, colour and all:
readpower() {
gpio mode 2 in
powerstate_raw=$(gpio read 2)
if [ "${powerstate_raw}" -eq 1 ]; then
powerstate="\e[32mOn\e[0m"
else
powerstate="\e[31mOff\e[0m"
fi
}
The entire code of the BMC "shell" can be found on my GitHub, and is called via a small hack to the /etc/passwd
file for the root
user, starting by default and terminating the SSH session on exit:
#root:x:0:0:root:/root:/bin/bash
root:x:0:0:root:/root:/root/bmc.sh
Finally we're able to set the host system's name (for display when logging in) via the file /etc/bmchost
, which makes deploying an image and setting the name trivial.
Conclusion
I hope you've found this post interesting and useful - if you have some IPMI-less systems you want to manage remotely, I definitely recommend you try it out. If you have any questions or comments, shoot me an e-mail!