1#!/bin/bash 2set -e 3set -u 4 5### Parameters for the installation. 6export TARGET_NFS_DIR="/srv/nfsroot/" 7export TARGET_TFTP_DIR="/srv/tftp/" 8export MIRROR="http://ftp.debian.org/debian/" 9export ETH="enp0s3" 10 11# Install packages that we need on the host system to install our PXE 12# environment, which includes dnsmasq as a dhcp-server and tftp-server and 13# nfs for the network files system. 14apt-get -y install debootstrap zip coreutils util-linux e2fsprogs dnsmasq \ 15 nfs-common nfs-kernel-server 16 17mkdir -p ${TARGET_NFS_DIR} 18mkdir -p ${TARGET_TFTP_DIR} 19 20# Build a basic rootfs system (This takes a while) 21debootstrap --arch i386 jessie ${TARGET_NFS_DIR} ${MIRROR} 22 23# Setup apt-get configuration on the new rootfs. 24cat > ${TARGET_NFS_DIR}/etc/apt/sources.list <<-EOT 25deb ${MIRROR} stable main contrib non-free 26deb-src ${MIRROR} stable main contrib non-free 27 28deb http://security.debian.org/ stable/updates main contrib non-free 29deb-src http://security.debian.org/ stable/updates main contrib non-free 30 31EOT 32 33# Setup the PXE network interfaces configuration. This is the configuration the 34# clients will use to bring up their network. Assumes that they have a single 35# LAN card. 36cat > ${TARGET_NFS_DIR}/etc/network/interfaces <<-EOT 37auto lo 38iface lo inet loopback 39 40allow-hotplug eth0 41iface eth0 inet dhcp 42EOT 43 44# Setup the nfs root in a way so we can chroot into it. 45mount -t proc none ${TARGET_NFS_DIR}/proc 46mount --bind /sys ${TARGET_NFS_DIR}/sys 47mount --bind /dev ${TARGET_NFS_DIR}/dev 48mount -t tmpfs none ${TARGET_NFS_DIR}/tmp 49 50cp /etc/resolv.conf ${TARGET_NFS_DIR}/etc/resolv.conf 51# Setup a hostname on the NFS root (This might confuse some applications, as 52# the hostname is random on each read) 53echo "pxeclient" > ${TARGET_NFS_DIR}/etc/hostname 54echo "127.0.0.1 pxeclient" >> ${TARGET_NFS_DIR}/etc/hosts 55# Setup /tmp as tmpfs on the netboot system, so we have a place to write 56# things to. 57cat > ${TARGET_NFS_DIR}/etc/fstab <<-EOT 58tmpfs /tmp tmpfs nodev,nosuid 0 0 59EOT 60 61# Get syslinux/pxelinux, which contains a lot of files, but we need some of 62# these to get PXE booting to work. 63sudo apt-get -y install pxelinux syslinux-efi 64mkdir -p ${TARGET_TFTP_DIR}/bios 65mkdir -p ${TARGET_TFTP_DIR}/efi32 66mkdir -p ${TARGET_TFTP_DIR}/efi64 67cp /usr/lib/PXELINUX/pxelinux.0 ${TARGET_TFTP_DIR}/bios/ 68cp /usr/lib/syslinux/modules/bios/*.c32 ${TARGET_TFTP_DIR}/bios/ 69cp /usr/lib/SYSLINUX.EFI/efi32/syslinux.efi ${TARGET_TFTP_DIR}/efi32/ 70cp /usr/lib/syslinux/modules/efi32/*.e32 ${TARGET_TFTP_DIR}/efi32/ 71cp /usr/lib/SYSLINUX.EFI/efi64/syslinux.efi ${TARGET_TFTP_DIR}/efi64/ 72cp /usr/lib/syslinux/modules/efi64/*.e64 ${TARGET_TFTP_DIR}/efi64/ 73 74# Setup the pxelinux configuration 75mkdir -p ${TARGET_TFTP_DIR}/pxelinux.cfg 76cat > ${TARGET_TFTP_DIR}/pxelinux.cfg/default <<-EOT 77DEFAULT linux 78LABEL linux 79KERNEL vmlinuz.img 80APPEND ro root=/dev/nfs nfsroot=192.168.55.1:${TARGET_NFS_DIR} initrd=initrd.img 81EOT 82ln -s ${TARGET_TFTP_DIR}/pxelinux.cfg ${TARGET_TFTP_DIR}/bios/pxelinux.cfg 83ln -s ${TARGET_TFTP_DIR}/pxelinux.cfg ${TARGET_TFTP_DIR}/efi32/pxelinux.cfg 84ln -s ${TARGET_TFTP_DIR}/pxelinux.cfg ${TARGET_TFTP_DIR}/efi64/pxelinux.cfg 85 86ln -s ${TARGET_TFTP_DIR}/vmlinuz.img ${TARGET_TFTP_DIR}/bios/vmlinuz.img 87ln -s ${TARGET_TFTP_DIR}/vmlinuz.img ${TARGET_TFTP_DIR}/efi32/vmlinuz.img 88ln -s ${TARGET_TFTP_DIR}/vmlinuz.img ${TARGET_TFTP_DIR}/efi64/vmlinuz.img 89 90ln -s ${TARGET_TFTP_DIR}/initrd.img ${TARGET_TFTP_DIR}/bios/initrd.img 91ln -s ${TARGET_TFTP_DIR}/initrd.img ${TARGET_TFTP_DIR}/efi32/initrd.img 92ln -s ${TARGET_TFTP_DIR}/initrd.img ${TARGET_TFTP_DIR}/efi64/initrd.img 93 94# Setup vmlinuz.img kernel in ${TARGET_TFTP_DIR} 95chroot ${TARGET_NFS_DIR} apt-get update 96chroot ${TARGET_NFS_DIR} apt-get -y install linux-image-686-pae firmware-linux-nonfree 97cp ${TARGET_NFS_DIR}/boot/vmlinuz* ${TARGET_TFTP_DIR}/vmlinuz.img 98cp ${TARGET_NFS_DIR}/boot/initrd.img* ${TARGET_TFTP_DIR}/initrd.img 99 100# Setup the export to the /etc/exports file, this will server our root trough 101# NFS after rebooting the system later. 102cat > /etc/exports <<-EOT 103${TARGET_NFS_DIR} *(ro,sync,no_root_squash,insecure) 104EOT 105 106# Setup the network interface to a static IP. 107cat > /etc/network/interfaces <<-EOT 108auto lo 109iface lo inet loopback 110 111allow-hotplug ${ETH} 112auto ${ETH} 113iface ${ETH} inet static 114 address 192.168.55.1 115 netmask 255.255.255.0 116 gateway 192.168.55.1 117EOT 118 119# Setup dnsmasq configuration to serve a PXE boot envirnoment, tftp-server, and 120# to serve as dhcp server (as PXE is handled with DHCP and TFTP) 121cat > /etc/dnsmasq.conf <<-EOT 122interface=${ETH} 123dhcp-range=192.168.55.10,192.168.55.254 124 125dhcp-boot=bios/pxelinux.0 126dhcp-match=set:efi32,option:client-arch,6 127dhcp-match=set:efi64,option:client-arch,7 128dhcp-match=set:efi64,option:client-arch,9 129dhcp-boot=tag:efi32,efi32/syslinux.efi 130dhcp-boot=tag:efi64,efi64/syslinux.efi 131 132enable-tftp 133tftp-root=${TARGET_TFTP_DIR} 134EOT 135 136# Disable some services to decrease boot time 137chroot ${TARGET_NFS_DIR} systemctl disable rsyslog 138 139# Install tools in NFS root required to build EE. 140chroot ${TARGET_NFS_DIR} apt-get update 141chroot ${TARGET_NFS_DIR} apt-get -y install git build-essential libx11-dev \ 142 cmake libxrandr-dev mesa-common-dev libglu1-mesa-dev libudev-dev \ 143 libglew-dev libjpeg-dev libfreetype6-dev libopenal-dev libsndfile1-dev \ 144 libxcb1-dev libxcb-image0-dev 145# Install basic X setup in NFS root to allow us to run EE later on. 146chroot ${TARGET_NFS_DIR} apt-get -y install xserver-xorg-core \ 147 xserver-xorg-input-all xserver-xorg-video-all xinit alsa-utils 148 149# Download&install SFML,EE,SP (This takes a while) 150chroot ${TARGET_NFS_DIR} git clone https://github.com/daid/EmptyEpsilon.git /root/EmptyEpsilon 151chroot ${TARGET_NFS_DIR} git clone https://github.com/daid/SeriousProton.git /root/SeriousProton 152chroot ${TARGET_NFS_DIR} apt-get -y install libsfml-* 153mkdir -p ${TARGET_NFS_DIR}/root/EmptyEpsilon/_build 154chroot ${TARGET_NFS_DIR} sh -c 'cd /root/EmptyEpsilon/_build && cmake .. -DSERIOUS_PROTON_DIR=$HOME/SeriousProton/ && make -j 3' 155# Create a symlink for the final executable. 156chroot ${TARGET_NFS_DIR} ln -s _build/EmptyEpsilon /root/EmptyEpsilon/EmptyEpsilon 157# Create a symlink to store the options.ini file in /tmp/, this so the client 158# can load a custom file. 159chroot ${TARGET_NFS_DIR} ln -s /tmp/options.ini /root/EmptyEpsilon/options.ini 160 161cat > ${TARGET_NFS_DIR}/root/setup_option_file.sh <<-EOT 162#!/bin/sh 163MAC=\$(cat /sys/class/net/eth0/address | sed 's/://g') 164if [ -e /root/configs/\${MAC}.ini ]; then 165 cp /root/configs/\${MAC}.ini /tmp/options.ini 166else 167 echo "instance_name=\${MAC}" > /tmp/options.ini 168fi 169EOT 170chmod +x ${TARGET_NFS_DIR}/root/setup_option_file.sh 171# Create a link to our client configuration tool, which helps in setting up 172# option files per client. 173ln -s ${TARGET_NFS_DIR}/root/EmptyEpsilon/netboot/config_manager.py ~/config_manager.py 174 175# Create an install a systemd unit that runs EE. 176cat > ${TARGET_NFS_DIR}/etc/systemd/system/emptyepsilon.service <<-EOT 177[Unit] 178Description=EmptyEpsilon 179 180[Service] 181Environment=XAUTHORITY=/tmp/.xauthority 182TimeoutStartSec=0 183WorkingDirectory=/root/EmptyEpsilon 184ExecStartPre=/root/setup_option_file.sh 185ExecStart=/usr/bin/startx /root/EmptyEpsilon/EmptyEpsilon -- -logfile /tmp/x.log 186 187[Install] 188WantedBy=multi-user.target 189EOT 190chroot ${TARGET_NFS_DIR} systemctl enable emptyepsilon.service 191 192# Disable screen standby/blanking 193mkdir -p ${TARGET_NFS_DIR}/etc/X11/xorg.conf.d 194cat > ${TARGET_NFS_DIR}/etc/X11/xorg.conf.d/10-monitor.config <<-EOT 195Section "Monitor" 196 Identifier "LVDS0" 197 Option "DPMS" "false" 198EndSection 199 200Section "ServerLayout" 201 Identifier "ServerLayout0" 202 Option "StandbyTime" "0" 203 Option "SuspendTime" "0" 204 Option "OffTime" "0" 205 Option "BlankTime" "0" 206EndSection 207EOT 208 209# Instead of running a login shell on tty1, run a normal shell so we do not 210# have to login with a username/password are just root. Who cares, we are on 211# a read only system. 212cat > ${TARGET_NFS_DIR}/etc/systemd/system/shell_on_tty.service <<-EOT 213[Unit] 214Description=Shell on TTY1 215After=getty.target 216Conflicts=getty@tty1.service 217 218[Service] 219Type=simple 220RemainAfterExit=yes 221ExecStart=/bin/bash 222TimeoutStopSec=1 223StandardInput=tty-force 224StandardOutput=inherit 225StandardError=inherit 226 227[Install] 228WantedBy=graphical.target 229EOT 230chroot ${TARGET_NFS_DIR} systemctl enable shell_on_tty.service 231 232# Install the ssh server on the netboot systems, so we can remotely access 233# them, setup a private key on the server and put the public on as authorized 234# key in the netboot system. Also install avahi for easier server discovery. 235chroot ${TARGET_NFS_DIR} apt-get install -y openssh-server avahi-daemon avahi-utils libnss-mdns 236echo "PermitRootLogin yes" >> ${TARGET_NFS_DIR}/etc/ssh/sshd_config 237if [[ ! -e $HOME/.ssh/id_rsa ]]; then 238 ssh-keygen -t rsa -f $HOME/.ssh/id_rsa -N '' 239fi 240mkdir -p ${TARGET_NFS_DIR}/root/.ssh/ 241cp $HOME/.ssh/id_rsa.pub ${TARGET_NFS_DIR}/root/.ssh/authorized_keys 242cat > ${TARGET_NFS_DIR}/etc/avahi/services/ee.service <<-EOT 243<?xml version="1.0" standalone='no'?> 244<!DOCTYPE service-group SYSTEM "avahi-service.dtd"> 245<service-group> 246 <name replace-wildcards="yes">EmptyEpsilon on %h</name> 247 <service> 248 <type>_emptyepsilon._tcp</type> 249 <port>22</port> 250 </service> 251</service-group> 252EOT 253 254# Install distcc, and setup distcc per default on all our netbooted clients. 255# Meaning we can speed up compiling of EE the more hosts we have. 256chroot ${TARGET_NFS_DIR} apt-get -y install distcc 257# Setup the distcc configuration for the clients. 258sed -ie 's/STARTDISTCC="false"/STARTDISTCC="true"/' ${TARGET_NFS_DIR}/etc/default/distcc 259sed -ie 's/ALLOWEDNETS="127.0.0.1"/ALLOWEDNETS="192.168.0.0\/16 172.16.0.0\/12 10.0.0.0\/8"/' ${TARGET_NFS_DIR}/etc/default/distcc 260sed -ie 's/LISTENER="127.0.0.1"/LISTENER="0.0.0.0"/' ${TARGET_NFS_DIR}/etc/default/distcc 261sed -ie "s/JOBS=\"\"/JOBS=\"2\"/" ${TARGET_NFS_DIR}/etc/default/distcc 262sed -ie 's/ZEROCONF="false"/ZEROCONF="true"/' ${TARGET_NFS_DIR}/etc/default/distcc 263 264# Create extra scripts to ease the maintenance of this machine. 265cat > /etc/network/interfaces.dhcp_client <<-EOT 266auto lo 267iface lo inet loopback 268 269allow-hotplug ${ETH} 270auto ${ETH} 271iface ${ETH} inet dhcp 272EOT 273 274cat > /root/dhcp_client.sh <<-EOT 275#!/bin/bash 276## Script to stop the dhcp server, and use the network port as normal client 277## port. So we can access other networks. 278systemctl stop dnsmasq 279ifdown -a 280ifup -a -i /etc/network/interfaces.dhcp_client 281EOT 282chmod +x /root/dhcp_client.sh 283 284cat > /root/dhcp_server.sh <<-EOT 285#!/bin/bash 286## Script to start the dhcp server, and use the network port to host the 287## network boot environment. (useful after switching to client with 288## dhcp_client.sh) 289systemctl stop dnsmasq 290ifdown -a 291ifup -a 292systemctl start dnsmasq 293EOT 294chmod +x /root/dhcp_server.sh 295 296cat > /root/update.sh <<-EOT 297#!/bin/bash 298## Script to update EE, assumes you have internet on this machine. 299mount -t proc none ${TARGET_NFS_DIR}/proc 300mount --bind /sys ${TARGET_NFS_DIR}/sys 301mount --bind /dev ${TARGET_NFS_DIR}/dev 302mount -t tmpfs none ${TARGET_NFS_DIR}/tmp 303 304cp /etc/resolv.conf ${TARGET_NFS_DIR}/etc/resolv.conf 305chroot ${TARGET_NFS_DIR} sh -c 'cd /root/SeriousProton/ && git pull' 306chroot ${TARGET_NFS_DIR} sh -c 'cd /root/EmptyEpsilon/ && git pull' 307chroot ${TARGET_NFS_DIR} sh -c 'cd /root/EmptyEpsilon/_build && cmake .. -DSERIOUS_PROTON_DIR=/root/SeriousProton/ && make -j 3' 308EOT 309chmod +x /root/update.sh 310