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

152 lines
13 KiB
Markdown

+++
class = "post"
date = "2017-02-10T01:35:38-05:00"
tags = []
title = "Build A Raspberry Pi BMC"
type = "post"
weight = 1
draft = false
+++
**NOTICE:** This project is long-since obsoleted. I never did complete it, and ended up just buying some IPMI-capable motherboards. I would receommend the various Pi-KVM solutions now available as much better, more robust replacements to this project.
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. After an incident with one machine while I was on vacation, I finally decided that they needed remote management, and I decided to make my own BMC for them rather than waste money on replacement (IPMI-capable) motherboards.
## Enter the Raspberry Pi
If you don't know what it is, the [Rapberry Pi](https://www.raspberrypi.org) is a small single-board computer, featuring an ARM SOC, Ethernet, USB, video, audio, and most importantly, GPIO (General-Purpose Input and Output) pins, which is powered by MicroUSB and running the Debian distribution '[Raspbian](https://www.raspberrypi.org/downloads/raspbian/)'. The GPIO pins allow one to control or read information with a simple utility or Python library, from various devices, including a serial console interface. These features make the Raspberry Pi a perfect fit for a BMC, and really not that far from the "real" BMCs found in most server-grade motherboards.
*(Pictured: A Raspberry Pi 1 model B)*
![Raspberry Pi](/images/rpibmc/rpi-1b.jpg)
## The hardware
### Power - thanks ATX!
One of the main ideas behind a BMC is that it should be accessible even if the host system is off. So we need some sort of power independent of the host state. The first thought when using a Raspberry Pi as a BMC would be to power it from some sort of external USB power brick, but that's messy: another cable running out of the case that must be dealt with, and another power brick. Luckily for us however, the ATX power supply standard has a solution!
The purple wire on a standard 24-pin ATX connector provides a standby +5V power supply, rated in the spec for up to 50mA but in reality today often supporting close to 1A. This is more than enough to run the motherboard standby power as well as a Raspberry Pi. This has the added benefit of working just like a real BMC: when the system is unplugged, the BMC also turns off, and turns back on as soon as power is reapplied. With that in mind, I made a simple "adapter" out of a piece of solid-core CAT5 cable and carefully encased in hot glue, which is inserted directly into the ATX motherboard connector, with the other end attached to a standard MicroUSB cable. The result is consistent, reliable, in-case power for the BMC without any trickery, and a cable tie keeps it locked in place.
[Editor's note: WARNING - This may burn down your computer - I will eventually make proper connectors, but I'm not letting that hold up the project!]
*(Pictured: The power interface to the motherboard, attached to a MicroUSB cable)*
[Picture - power stuff]
### GPIO to rule them all
Once of a BMC's main functions is controlling and determining the power state of the system. This basic functionality allows you to, for instance, hard reset a crashed machine, or start it back up after a power failure. No more running for the box to press the power button!
The Raspberry Pi's GPIO pins provide a nice simple method for interfacing with the raw system management headers on any motherboard. For determining the power state, a GPIO pin is connected with a small resistor directly to the Power LED connector on the motherboard. When this pin is read high, we know the system is online; when it's low, we know it's offline. Probably the simplest circuit in the project!
The power and reset switches are a little more complex. While you can direct the GPIO directly to the switch headers, this will not work as you would expect, and could in fact risk blowing out your motherboard by sending 3.3V into the switch headers. The solution is to use a transistor, and from my basic understanding any would do: connect the base pin of the transistor to your GPIO pin, and the collector and emitter pins to the switch header (emitter to ground). The result is an electrically controlled switch, which turns on when the GPIO is set high for a second, and turns off again when the GPIO is set low. You can now safely control the power and reset switches with your Raspberry Pi.
*(Pictured: the GPIO layout for a first-generation model-B Raspberry Pi)*
![GPIO pinout](/images/rpibmc/rpi-1b-gpio.png)
### Serial - USB or TTL?
Another critical function of a BMC is to manage the host system without requiring a connected monitor+keyboard. Luckily just about every motherboard, and especially "server-grade" motherboards that otherwise lack a BMC, still feature one or two DB9 COM ports and console redirection. With some BIOS configurations, console redirection lets you send the console output through the serial port, giving us an old-school VTY terminal: exactly what we need for console access. However getting that console into the Raspberry Pi is a bit tricky.
The most common way to do this is to use a USB to Serial adapter, but like the original power suggestion, it's messy in terms of cabling, requiring a header, crossover cable, and then the adapter itself. Enter the TTL serial port on the Raspberry Pi. Built in to [GPIO pins 14 and 15](http://codeandlife.com/2012/07/01/raspberry-pi-serial-console-with-max3232cpe/), the Raspberry Pi features a TTL 3.3V serial interface. Normally you would use this to get a console into the Raspberry Pi itself, but with a simple flip of the TXD and RXD lines and some [reconfiguration of the Raspbian image](http://www.hobbytronics.co.uk/raspberry-pi-serial-port), we can use this interface to communicate with the host system instead.
This method does require a special chip called the MAX3232, which will convert between TTL serial from the Raspberry Pi and the RS232 serial of the motherboard. Luckily, the converter chips can be had for about $1.50 for 5 on eBay from the right Chinese sellers, including the capacitors you need to make the circuit work. And with some jumpers, we can connect the chip directly to the motherboard COM2 header; no messy crossover cables or USB to serial adapters! The resulting device is `/dev/ttyAMA0` in Raspbian and works flawlessly with your terminal emulator of choice; I'm using screen to allow persistence and clean disconnection without terminating the serial session (more on that later!)
The one downside of this method is the lack of proper VGA graphics support. Your OS needs to be text-based with support for console redirection, such as any Unix-like OS or possibly Windows Core (I don't know), and it needs to be configured with this support to get anywhere past the BIOS. As I'm using Debian on all my systems this is perfectly fine by me and I include the tweaks into my system images, but keep this in mind when setting up your BMC.
*(Pictured: the MAX3232 signal converter board)*
![MAX3232 Serial boards](/images/rpibmc/max3232-boards.jpg)
### Cabling it up
The actual cabling is kept simple using a solderable breadboard. Each cell features a total of 26 header pins for female-to-female jumper cables, along with the two transistors, two resistors, and the MAX3232 daughter board. This unit keeps all the cabling neat and consistent between all three of my systems, and makes documenting the connections a breeze!
The board layout is straightforward and rendered here in ASCII for convenience, where each line (a connection), character (Transistor, Resistor), or number (header pin) represents one hole on the breadboard. The transistor leads are labeled Emitter, Base, and Collector.
```
[01][02][03][04][05][06][07][08][09][10]
| | | | | | | | | |
[11][12][13][14] | | . . . .
| | | | | | |---|---|---|
E \ / C E \ / C | | | |
T T | | | MAX |
B / /---/ B | | | 3232 |
| | | | | BOARD |
| | [15][16] | | | |
| | | | | | |---|---|---|
| | . | . | . . . .
| | R | R | | | | |
[17][18][19][20][21][22][23][24][25][26]
Motherboard connectors:
01: Reset ground 02: Reset signal
02: Power ground 04: Power signal
05: Power LED ground 06: Power LED signal
07: RS232 RX 08: RS232 TX
09: RS232 3.3V 10: RS232 ground
Chassis connectors:
11: Reset switch ground 12: Reset switch signal
13: Power switch ground 14: Power switch signal
15: Chassis LED ground 16: Chassis LED signal
Raspberry Pi connectors:
17: Reset GPIO [0] 18: Power GPIO [1]
19: GPIO ground 20: Power LED GPIO [3]
21: GPIO ground 22: Power State GPIO [2]
23: TTL ground 24: TTL 3.3V
25: TTL TX 26: TTL RX
```
The finished product is a small board that keeps all the cabling neat and tidy in the case, and is easily mounted. While my soldering job is attrocious, they work!
*(Pictured: The finished breadboard layout)*
![The finished breadboard](/images/rpibmc/breadboard-layout.jpg)
*(Pictured: the cabling of the Raspberry Pi BMC)*
![The finished product](/images/rpibmc/finished-product.jpg)
## The software
Most traditional BMCs are managed via a (usually-terrible) Web UI, which is often prone to breakage of various kinds. And often these Web UIs 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 Flash web page, Java plugins, or slow 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 programs doing the heavy lifting are 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 via `rc.local`, to ensure all serial output is captured and stored for later analysis, even from cold boot - 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 BMC shell in `bash`, I was able to get all the flexibility I wanted without any programming overhead; the whole thing is under 200 lines including all the functions and a little prep work ensuring the required packages are installed. The whole code of the `bmc.sh` utility script can be found [on my GitHub](https://github.com/joshuaboniface/rpibmc), and is fairly self-explanatory.
The BMC is accessible via a user called `bmc`, which has the `bmc.sh` script as its login shell, as well as the groups required to run the various functions (`sudo` and `gpio` specifically). The `/etc/sudoers` file has also been edited to allow sudo without a password, which is used within the `bmc.sh` script. The new user can be created and configured on fresh install of Raspbian using these commands, and assuming `bmc.sh` is in `/bin`:
```
sudo sed -i 's/%sudo\tALL=(ALL:ALL) ALL/%sudo\tALL=(ALL:ALL) NOPASSWD: ALL/' /etc/sudoers
sudo useradd -g sudo -G gpio -s /bin/bmc.sh -d /home/bmc -m bmc
sudo chpasswd <<<"bmc:password"
```
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. Log in as the 'bmc' user via SSH, and observe:
*(Pictured: an example session with `bmc.sh`)*
![Shell example](/images/rpibmc/bmcshell-sample.png)
*(Pictured: Debian Live via the serial console)*
![Console example](/images/console.png)
## 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. So far my testing has been extremely positive; for under $40 (if you can find the Raspberry Pi for the right price; a first generation is more than powerful enough), you can build youself out-of-band BMC management for any motherboard you can find. And the remote management makes even the most irritating host messups ("Oh broke my udev network rules, again!?") trivial to recover from. A small price to pay for the peace of mind of being able to manage your system from almost anywhere, even a cruise ship!
*(Pictured: what you might have to do on a cruise ship without a BMC!)*
![No BMC fail](/images/nobmcfail.png)
If you have any questions or comments, shoot me an e-mail, or find me on various social media!