/ SmartOS

SmartOS via iPXE Using a Raspberry Pi

SmartOS is awesome - rewriting the usbkey not that awesome. While I was testing some extensions to the platform image rewriting the usbkey annoyed me a lot. I decided to boot that beutiful development box using iPXE and got my RaspberryPi to act as the actual server.

raw plan

Get a RaspberryPi to act as dhcp server and serve iPXE via tftp to hosts who don’t have iPXE in a rom. iPXE will fetch the rest of needed data via http (because it’s just faster than tftp).

stuff used

  • RaspberryPi board (model B with 512M ram; plus some working power source)
  • 8G SD-card (2G is enough; more is just for storing more boot images)
  • 8G usbkey (not needed; to store boot images; it’s faster than my SD-card)
  • some SD-card reader to write the OS image onto the SD-card
  • some HDMI display and keyboard to setup sshd
  • Arch Linux ARM (I’m using archlinux-hf-2013-01-22; get it from raspberrypi.org/downloads)
  • iPXE (compile it yourself or use precompiled binaries; I use this ipxe.tar.bz2)

I’m using the Arch Linux ARM port because I like pacman more than apt. Basically every Linux should work the same if you substitude the pacman commands.

I assume that you know how to use dd to write the OS to the actual SD-card and got that done before reading further.
How to know if it’s done? - If the Pi can boot of the SD-card you’re ready to move on :)

setting up sshd and a static ip

That’s (for me) the hardest part because i can’t just copy&paste stuff ;)

We’ll configure the Pi to use a static IP on our current network so we can use ssh to configure the rest. For this we need to create a service and it’s configuration file:

CONNECTION='ethernet'
DESCRIPTION='A basic static ethernet connection using iproute'
INTERFACE='eth0'
IP='static'
ADDR='192.168.1.250'
#ROUTES=('192.168.0.0/24 via 192.168.1.2')
GATEWAY='192.168.1.1'
DNS=('8.8.8.8' '8.8.4.4')

To apply this configuration we simply need to restart the netcfg service:

$ systemctl restart netcfg

Now you can disconnect the Pi from the display and the keyboard and continue to work remotely.

basic configuration and updating the system

You should set some password for root maybe or configuring the hostname.

As soon as we have working name resolves we can use pacman to update/upgrade our system:

$ pacman -Syu
$ reboot

getting dhcpd and tftpd up and running

$ pacman -Sy dhcp tftp-hpa

Now we need to configure the dhcp server. I’ll chainload iPXE because some of my boxes don’t let me reflash their roms.

# dhcpd.conf
#

option domain-name "l.l0cal.net";
option domain-name-servers 8.8.8.8, 8.8.4.4;

default-lease-time 600;
max-lease-time 7200;

log-facility local7;

subnet 192.168.1.0 netmask 255.255.255.0 {
  pool {
    range dynamic-bootp 192.168.1.100 192.168.1.200;

    option broadcast-address 192.168.1.255;
    option routers 192.168.1.1;

    next-server 192.168.1.250;

    if exists user-class and option user-class = "iPXE" {
      filename "menu.ipxe";
    } else {
      filename "undionly.kpxe";
    }
  }
}

To install iPXE (undionly.kpxe) we simply extract the file to the tftp directory:

$ curl https://dl.dropboxusercontent.com/u/2265989/SmartOS/ipxe.tar.bz2 | tar -xjC /srv/tftp undionly.kpxe

The second important file is the iPXE script that gets executed automatically on boot. For now we’ll add a simple ipxe menu script to test the configuration. The SmartOS parts will be added later.

#!ipxe

:start
menu Welcome to iPXE's Boot Menu
item
item shell      Enter iPXE shell
item reboot     Reboot
item
item exit       Exit (boot local disk)
choose --default exit --timeout 30000 target && goto ${target}

:shell
echo Type exit to get the back to the menu
shell
set menu-timeout 0
goto start

:reboot
reboot

:exit
exit
$ systemctl enable tftpd.socket
$ systemctl start tftpd.socket
$ systemctl enable dhcpd4
$ systemctl start dhcpd4

This should give us a running dhcp server for our network. It should automatically boot a client to iPXE and load the menu script.

We should be able to boot a client now and get the iPXE boot menu. I tested that in VMware Fusion and got the folowing:

iPXE booting inside VMware Fusion 5

If that is not working - something is wrong on you setup. Ensure the the RaspberryPi is the dhcp server your box is using and ensure that all services are running - If unsure just reboot the Pi that should take only some seconds.

If the basic boot into iPXE is working we can start adding SmartOS to the boot menu.

prepare a http server to serve images

I want to use an http server to serve bootable images. This is mainly done for speed reasons because tftp is rather slow. We’ll add a simple http server to the Pi. It can be mostly any http server but I’ll use darkhttpd because it’s the smalest static-only http server I found in the package list.

$ pacman -Sy darkhttpd
$ mkdir -p /srv/http

darkhttpd has no configuration file - It simply takes a folder name as argument and serves everything in there. But as long as we want to run that at bootup automatically we need to create a systemd service description:

[Unit]
Description=darkhttpd server deamon
After=network.target

[Service]
Type=simple
ExecStart=/usr/sbin/darkhttpd /srv/http
ExecStop=/bin/kill $MAINPID
ExecReload=/bin/kill $MAINPID ; /usr/sbin/darkhttpd /srv/http

[Install]
WantedBy=multi-user.target
$ systemctl enable darkhttpd
$ systemctl start darkhttpd

If we now test the httpd server it should be running and ready to serve files:

$ curl -I http://192.168.1.250/
HTTP/1.1 200 OK
Date: Sat, 02 Feb 2013 15:39:44 GMT
Server: darkhttpd/1.8
Accept-Ranges: bytes
Keep-Alive: timeout=60
Content-Length: 182
Content-Type: text/html

adding SmartOS images to the menu

$ mkdir -p /srv/http/smartos/20130125T031721Z
$ curl https://download.joyent.com/pub/iso/platform-20130125T031721Z.tgz | tar -xzC /srv/http/smartos/20130125T031721Z
$ mv /srv/http/smartos/20130125T031721Z/platform-20130125T031721Z /srv/http/smartos/20130125T031721Z/platform

It is important to have the platform directory in path else SmartOS will spit out errors on bootup. So we end up with a folder structure like .../smartos/<version>/platform/i86pc/... for every SmartOS release we add.

And finally we need to alter the menu.ipxe file a bit and add our SmartOS seletors:

#!ipxe

set smartos-build 20130125T031721Z

:start
menu Welcome to iPXE's Boot Menu
item
item --gap -- ------------------------- Operating systems ------------------------------
item smartos            Boot SmartOS (${smartos-build})
item smartos_noimport   Boot SmartOS (${smartos-build}) noimport
item --gap -- ------------------------------ Utilities ---------------------------------
item shell      Enter iPXE shell
item reboot     Reboot
item
item exit       Exit (boot local disk)
choose --default smartos --timeout 30000 target && goto ${target}

:shell
echo Type exit to get the back to the menu
shell
set menu-timeout 0
goto start

:reboot
reboot

:exit
exit

:smartos
kernel http://192.168.1.250/smartos/${smartos-build}/platform/i86pc/kernel/amd64/unix -B console=text,root_shadow='$5$2HOHRnK3$NvLlm.1KQBbB0WjoP7xcIwGnllhzp2HnT.mDO7DpxYA',smartos=true
module http://192.168.1.250/smartos/${smartos-build}/platform/i86pc/amd64/boot_archive
boot
goto start

:smartos_noimport
kernel http://192.168.1.250/smartos/${smartos-build}/platform/i86pc/kernel/amd64/unix -B console=text,root_shadow='$5$2HOHRnK3$NvLlm.1KQBbB0WjoP7xcIwGnllhzp2HnT.mDO7DpxYA',smartos=true,noimport=true
module http://192.168.1.250/smartos/${smartos-build}/platform/i86pc/amd64/boot_archive
boot
goto start

Here we go - everything set up. Now we should be able to reboot our SmartOS box and serve the SmartOS platform via iPXE. It is also possible to serve those platform images from a remote server over WAN. My build server is sitting in some datacenter and I’ll add some extra stuff to boot my box directly from the build server - maybe I’ll also open up that server for every one else - have to think about that :)