blog/content/post/a-raspberry-pi-bmc.md

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.

Shell example

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!