Hey guys,
today I’d like to tell you about Shoelaces from Thousandeyes. Shoelaces may be used to automate Server installation with iPXE Boot.
If you are already familiar with the basics about PXE, iPXE and how to set up the environment you can go ahead to Shoelaces Setup.

Environment

Before I dig into the details I prepared an Image to show you the Software Stack and also the whole server set up.

Software Stack and Server Setup

All commands are executed on a server named pxe-server.local with IP 192.168.0.2 running on CentOS 7.4.

DHCPD (ISC DHCP)

The DHCP Server is the first line of the stack. As soon as the Client boot in PXE Mode, it requests an IP Address and receives an IP address with the command where it can find the Image to boot from.
I prepared an example configuration file below.

[email protected]:[~]: cat /etc/dhcp/dhcpd.conf
subnet 192.168.0.0 netmask 255.255.255.0 {
  range 192.168.0.10 192.168.0.20;
  option subnet-mask 255.255.255.0;
  option routers 192.168.0.1;
  option domain-name-servers 192.168.0.1;
  next-server 192.168.0.2;
  if exists user-class and option user-class = "iPXE" {
    filename "http://192.168.0.2/poll/1/${netX/mac:hexhyp}";
  } else {
    filename "undionly.kpxe";
  }
}

As you can see the DHCP Server manages the IP Range 192.168.0.10-20 and also sends the next-server option which tells the client to boot from 192.168.0.2:69/filename (TFTP Server) option. If the Client supports iPXE it boots from http://192.168.0.2/poll/1/${netX/mac:hexhyp} which is Shoelaces. If the client doesn’t support iPXE it boots a microkernel which supports iPXE.

You can test your DHCP Settings with nmap


[email protected]:[~]: nmap --script broadcast-dhcp-discover
 
Starting Nmap 6.40 ( http://nmap.org ) at 2018-08-06 12:58 UTC
Pre-scan script results:
| broadcast-dhcp-discover:
|   IP Offered: 192.168.0.10
|   DHCP Message Type: DHCPOFFER
|   Server Identifier: 192.168.0.2
|   IP Address Lease Time: 0 days, 0:05:00
|   Subnet Mask: 255.255.255.0
|   Router: 192.168.0.1
|_  Domain Name Server: 192.168.0.1
WARNING: No targets were specified, so 0 hosts scanned.
Nmap done: 0 IP addresses (0 hosts up) scanned in 0.07 seconds

TFTP

The TFTP Server is needed to serve the undionly.kpxe when the client doesn’t support iPXE.

To “install” the microkernel you need to download the file from ipxe.org and save it into /var/lib/tftpboot.

[email protected]:[~]: wget -P /var/lib/tftpboot https://boot.ipxe.org/undionly.kpxe

Xinetd

You need Xinetd to actually serve the microkernel.

Here is the config file we used to glue tftp and Xinetd together:

[email protected]:[~]: cat /etc/xinetd.d/tftp
{
    socket_type     = dgram
    protocol        = udp
    wait            = yes
    user            = root
    server          = /usr/sbin/in.tftpd
    server_args     = -s /var/lib/tftpboot
    disable         = no
    per_source      = 11
    cps             = 100 2
    flags           = IPv4
}

As soon as you created the config file you need to restart xinetd and check if the tftp module is running.

[email protected]:[~]: systemctl status xinetd.service
● xinetd.service - Xinetd A Powerful Replacement For Inetd
   Loaded: loaded (/usr/lib/systemd/system/xinetd.service; enabled; vendor preset: enabled)
   Active: active (running) since Mo 2018-08-11 15:19:41 UTC; 3s ago
  Process: 8060 ExecStart=/usr/sbin/xinetd -stayalive -pidfile /var/run/xinetd.pid $EXTRAOPTIONS (code=exited, status=0/SUCCESS)
 Main PID: 8061 (xinetd)
   CGroup: /system.slice/xinetd.service
           └─8061 /usr/sbin/xinetd -stayalive -pidfile /var/run/xinetd.pid
 
Aug 11 15:19:41 pxe-server xinetd[8061]: removing daytime
Aug 11 15:19:41 pxe-server xinetd[8061]: removing discard
Aug 11 15:19:41 pxe-server xinetd[8061]: removing discard
Aug 11 15:19:41 pxe-server xinetd[8061]: removing echo
Aug 11 15:19:41 pxe-server xinetd[8061]: removing echo
Aug 11 15:19:41 pxe-server xinetd[8061]: removing tcpmux
Aug 11 15:19:41 pxe-server xinetd[8061]: removing time
Aug 11 15:19:41 pxe-server xinetd[8061]: removing time
Aug 11 15:19:41 pxe-server xinetd[8061]: xinetd Version 2.3.15 started with libwrap loadavg labeled-networking options compiled in.
Aug 11 15:19:41 pxe-server xinetd[8061]: Started working: 1 available service
[email protected]:[~]: netstat -tulpen | grep xinetd
udp        0      0 0.0.0.0:69              0.0.0.0:*                           0          235681     8061/xinetd

When you execute the status command at the end of the log should be at least ‘1’ available service printed. The Port 69/UDP should be open as well.

Shoelaces

Now we’re running the basic iPXE Environment. At the moment we are able to boot a client with PXE boot, obtain an IP Address and boot the iPXE microkernel if the client doesn’t support iPXE.

But what happens if the client boot with this line (which we configured in the dhcpd section)?
http://192.168.0.2/poll/1/${netX/mac:hexhyp}
Before answering the question I’ll guide you through the shoelaces installation.

Installation

Shoelaces is a program written in Go Lang. Therefore we need to install go at first.

# Determine your needed go version at https://golang.org/dl/#stable first. I need the amd64 binary which is version 1.10.3 at the moment.
[email protected]:[~]: wget https://dl.google.com/go/go1.10.3.linux-amd64.tar.gz
[email protected]:[~]: tar -xvf go1.10.3.linux-amd64.tar.gz
[email protected]:[~]: mv go /usr/local
[email protected]:[~]: echo "export GOROOT=/usr/local/go" >> /etc/bashrc
[email protected]:[~]: echo "export GOPATH=/opt/go" >> /etc/bashrc
[email protected]:[~]: echo "export PATH=$GOPATH/bin:$GOROOT/bin:$PATH" >> /etc/bashrc
[email protected]:[~]: src /etc/bashrc

To install shoelaces you need to get the repository with go get then you need to build the shoelaces binary.

[email protected]:[~]: go get github.com/thousandeyes/shoelaces
[email protected]:[~]: cd $GOPATH/src/github.com/thousandeyes/shoelaces
[email protected]:[~]: go build

Daemonize

Currently, we’re only able to start the service on demand with a command.

[email protected]:[~]: cd $GOPATH/src/github.com/thousandeyes/shoelaces
[email protected]:[~]: ./shoelaces -config configs/shoelaces.conf

But if you want the process permanently running you need to create a systemd file.
Luckily I already created one which needs a user to be created.

[email protected]:[~]: useradd shoelaces
[email protected]:[~]: cat /lib/systemd/system/shoelaces.service
[Unit]
Description=Shoelaces
Documentation=https://github.com/thousandeyes/shoelaces
ConditionPathExists=/opt/go/src/github.com/thousandeyes/shoelaces
After=network.target

[Service]
User=shoelaces

# Restart Policy
Restart=on-failure
RestartSec=10

# Execution
ExecStartPre=/bin/chown -R shoelaces /opt/go/src/github.com/thousandeyes/shoelaces
ExecStartPre=/bin/chmod u+x /opt/go/src/github.com/thousandeyes/shoelaces/shoelaces
ExecStart=/opt/go/src/github.com/thousandeyes/shoelaces/shoelaces -config configs/shoelaces.conf

# Environment
WorkingDirectory=/opt/go/src/github.com/thousandeyes/shoelaces
PermissionsStartOnly=true
NonBlocking=true

# Logging
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=shoelaces

[Install]
WantedBy=multi-user.target

After you added the content to the file /lib/systemd/system/shoelaces.service execute systemctl daemon-reload; systemctl start shoelaces.service; systemctl status shoelaces.service to start the service and check the status. You can always take a look into logs if you execute journalctl -f -u shoelaces.service.

Configure

I guess you already noticed the only missing part. Configuring Shoelaces.

It’s straight forward and fairly easy. Just go into the shoelaces directory and take a look at the default config file.

[email protected]:[~]: cd $GOPATH/src/github.com/thousandeyes/shoelaces
[email protected]:[/opt/go/src/github.com/thousandeyes/shoelaces]: cat configs/shoelaces.conf
port=8081
domain=localhost
data-dir=configs/example-templates-configs/
template-extension=.slc
mappings-file=mappings.yaml
debug=true

For production I changed the config file to the following one …

[email protected]:[/opt/go/src/github.com/thousandeyes/shoelaces]: cat configs/shoelaces.conf
port=8080
domain=192.168.0.2
data-dir=configs/templates-configs/
template-extension=.slc
mappings-file=mappings.yaml
debug=true

… and moved configs/example-templates-configs to configs/templates-configs.

Starting

Recently we changed the config file. Therefore you need to restart your service.

Now open your shoelaces URL (http://<domain>:<port>) with your favourite browser. If everything went well you should see the following website. If not, take a look into the logs what’s wrong with shoelaces.

Shoelaces Startup Image

Deep Dive

Back to the question before the shoelaces installation.

But what happens if the client boot with this line (which we configured in the dhcpd section)?
http://192.168.0.2/poll/1/${netX/mac:hexhyp}

The client connects to shoelaces and kept in a waiting loop until the user executes a “Boot!” command or shoelaces is able to bootstrap the server with ‘mappings’. This state looks like this:

Server Registered

As soon as you click on ‘Select an iPXE script’ you are able to choose an iPXE script located in $GOPATH/src/github.com/thousandeyes/shoelaces/configs/templates-configs/ipxe.

I clicked on centos.ipxe and filled out both arguments. If you check $GOPATH/src/github.com/thousandeyes/shoelaces/configs/templates-configs/ipxe/centos.ipxe.slc there are two strings which look like {{.<STRING>}}. These strings are the arguments shown in the UI.

[email protected]:[~]: cat $GOPATH/src/github.com/thousandeyes/shoelaces/configs/example-templates-configs/ipxe/centos.ipxe.slc
{{define "centos.ipxe" -}}
#!ipxe
set hostname {{.hostname}}
set release {{.release}}
set base http://mirror.centos.org/centos/${release}/os/x86_64

echo This automatically overwrites data!
echo CentOS ${release}
echo Installing ${hostname}

kernel ${base}/images/pxeboot/vmlinuz initrd=initrd.img repo=${base} ks=http://{{.baseURL}}/configs/centos.ks?hostname=$hostname&release=$release
initrd ${base}/images/pxeboot/initrd.img
boot
{{end}}

As soon as I click on the big red button “Boot!” the client leaves the waiting loop and starts to execute the iPXE script. It depends on your kickstart file how long it takes until your client is back again but normally it should’nt take longer than 10 minutes.

Conclusion

Shoelaces is a very small footprint software written in go which supports bootstrapping a huge amount of server. Even in a small environment, it helps a lot. Take a look at their Github Project Site if you want to discover all further features.

For example you may use the mapping feature if you want to bootstrap server automatically based on IP or Hostname pattern.

Leave a comment or contribute to the project if you like the software.


Marvyn Zalewski

Marvyn Zalewski

Marvyn is a nerdy guy which is into Linux and everything connected to it. He also loves to automate his home and build up a home lab which includes e.G. a custom steam machine and backup automation. He loves to hear EDM music and try to become a gin enthusiast.

Leave a Reply

Your email address will not be published.

5 × two =