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.

All commands are executed on a server named
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
To “install” the microkernel you need to download the file from ipxe.org and save it into /var/lib/
[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
Before answering the question I’ll guide you through the shoelaces installation.
Installation
# 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
[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
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/
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 (

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:

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.
0 Comments