Thursday 22 November 2018

Pi Network boot and PXR booting Centos via Ubuntu

Introduction[edit]

We're going to need a server, it will offer kernel boot images over TFTP, then filesystems over NFS. We'll used one SD card to convert Pi's, which we call "Magic Card" and another SD card will be the "Gold image" which will become the kernel and filesystem later used by the network client.

Setting up DHCP/TFTP[edit]

Install DHCP server ( Needs to be done on Server )[edit]

  • for Debian based system
sudo apt-get install isc-dhcp-server
  • for RHEL based system
sudo yum -y install dhcp
In both cases the config will be as follow:
subnet 192.168.0.0 netmask 255.255.255.0 {
 range 192.168.0.20 192.168.0.250;
 option broadcast-address 192.168.0.255;
 option routers 192.168.0.1;
 option subnet-mask 255.255.255.0;
 option domain-name "pxe.server";
 option domain-name-servers 10.161.0.1, 192.168.0.99, 8.8.8.8;
 next-server 192.168.0.15;
 option tftp-server-name "192.168.0.15";
 filename "pxelinux.0";
}

Install TFTP server ( Needs to be done on Server )[edit]

  • for Debian based system
sudo apt-get install -y syslinux tftpd tftp pxelinux
  • for RHEL based system
sudo yum -y install syslinux xinetd tftp-server
Edit the file /etc/xinetd.d/tftp:
service tftp
{
protocol        = udp
port            = 69
socket_type     = dgram
wait            = yes
user            = nobody
server          = /usr/sbin/in.tftpd
server_args     = /tftpboot
disable         = no
}
Start the relevant services as:
sudo systemctl start xinetd 
sudo systemctl enable xinetd

Install DNSMASQ server ( Needs to be done on Server )[edit]

Incase of existing DHCP server, we need a dhcp server which can work in proxy mode to fit into the existing system, here are the steps to achieve the said task:
  • for Debian based system
sudo apt -y install dnsmasq
  • for RHEL based system
sudo yum -y install dnsmasq
Configure DNS MASQ to work with existing system:
sudo nano /etc/dnsmasq.conf
Copy paste the following configuration:
port=0
dhcp-range=192.168.0.0,proxy
log-dhcp
enable-tftp
tftp-root=/tftpboot
pxe-service=0,"Raspberry Pi Boot"
dhcp-boot=pxelinux.0,pxeserver,192.168.0.15
pxe-service=X86PC, "Boot BIOS PXE", pxelinux.0
Edit the following file:
sudo vim /etc/default/dnsmasq
Enter the following entry in the last line:
DNSMASQ_EXCEPT=lo
Enable and restart the service:
systemctl enable dnsmasq
systemctl restart dnsmasq

Creating boot sequence[edit]

Preparing SD card[edit]

  • Flash the sd card with normal rasbian lite image from the following URL:
https://downloads.raspberrypi.org/raspbian_lite_latest
  • Once that is done, we need to install small package on the sd card:
sudo apt update && sudo apt upgrade -y
apt install ./eyemagnet-magiccard_0.1_armhf.deb
  • Once complete reboot the pi.
  • Re-Login and you will be presented with options.(The package is avaiable on Web-00 server in the unstable repo) Ignore for now and quit to complete the setup.

Serve kernel file[edit]

Using the same sdcard that we prepared for network booting and copy the boot directory to the tftp server.
All the contents of that (boot) directory of the sdcard shall be available in /tftpboot/workingbootcode directory on the server.
Once complete go the tftp server root directory and issue the following command:
ln -s workingbootcode/bootcode.bin .
This will setup the tftp server to start serving the kernel.

Modifying boot file[edit]

We need to edit the main cmdline.txt in the workingbootcode directory on the tftp server to reflect our nfs root which will be mounted when the pi boots up, this is as follows:
selinux=0 dwc_otg.lpm_enable=0 rootwait rw nfsroot=192.168.0.15:/nfs/image,v3 ip=dhcp root=/dev/nfs console=tty1 elevator=deadline logo.nologo vt.global_cursor_default=0 plymouth.enable=0
  • All the steps can be done via staying inside the pi, once complete shutdown this pi.

Creating the Main Image[edit]

'Clone' the filesystem[edit]

  • Needs to be done a freshly built pi ( To be done on a completely separate pi )
Disable Swap
sudo dphys-swapfile swapoff
sudo dphys-swapfile uninstall
sudo update-rc.d dphys-swapfile remove
Once the Pi has rebooted, locally or via SSH, run:
sudo mkdir -p /nfs/image
sudo rsync -xa --progress --exclude /nfs / /nfs/image
Note: You must do this on a running Pi, copying off the SDK card on another host did not appear to work.
cd /nfs/image
sudo mount --bind /dev dev
sudo mount --bind /sys sys
sudo mount --bind /proc proc
sudo umount dev
sudo umount sys
sudo umount proc
Remove the duplicated swap file if it exists:
sudo rm /nfs/image/var/swap
Create a tar archive of the nfs folder (The -p flag should preserve permissions etc.)
sudo tar -cpf /nfs.tar /nfs
Finally this archive needs to end up on the Server.
rsync -zavP /nfs.tar <Username>@<serverip>:/home/nfs.tar

Setting up NFS[edit]

Nfs server ( Needs to be done on Server )[edit]

Install the nfs service
  • for Debian based system
sudo apt-get install -y nfs-kernel-server
  • for RHEL based system
sudo yum -y install nfs-utils

Serve Image ( Needs to be done on Server )[edit]

Now go the home directory and issue the following command:
sudo tar --same-owner -xvf nfs.tar
Remove all other entries from the fstab file /nfs/image/etc/fstab so that it only contains the proc entry as follows:
proc            /proc           proc    defaults          0       0
Now move the content:
sudo mv nfs /
Edit the exports file:
/nfs/image *(rw,sync,no_subtree_check,no_root_squash)
Start service:
  • for Debian based system
sudo systemctl enable rpcbind nfs-kernel-server
sudo systemctl restart rpcbind nfs-kernel-server
  • for RHEL based system
sudo systemctl start rpcbind nfs-server 
sudo systemctl enable rpcbind nfs-server
Issue the folliwng command to make it active:
exportfs -rv

Pi Identity[edit]

Final boot[edit]

Now boot the pi with the same magic pi card, you will be greeted as follows)
Welcome to Pi Nework boot creator...
Boot mode fine :) (17:3020000a)
Enter the Remote TFTP server IP...: 192.168.0.15
Please enter your choice:
1) Create Image on Server and Reboot       
2) Just reboot       
3) Shutdown          
4) Remove Image from Server
5) Check firmware        
6) Update Firmware to enable Network Boot
7) Quit
Select Option 1 to create the identity.
Once complete it will make the pi reboot automatically.
Re-login to the pi and you will be present with the same display, but this time select Option 3.
Slide the magic card out and boot.
The pi will boot of the network server.

Thursday 8 November 2018

PXE ready a Pi

#!/bin/bash

function imagemaker {
echo "Your Device Identity is $(tput setaf 1)$(tput bold)$1$(tput sgr0)"
echo "Your Device IP Address after network boot will be: $(tput setaf 1)$(tput bold)$2$(tput sgr0)"
if [ ! -d /tftpboot/$1 ]
  then
mkdir -p /tftpboot/$1
cd /tftpboot/$1
ln -s ../workingbootcode/* .
cp cmdline.txt cmdline.txt.default
rm -f cmdline.txt
cat cmdline.txt.default | sed s/westpac/$1/g > cmdline.txt
rm -f cmdline.txt.default
mkdir /nfs/$1
cd /nfs/$1
echo
echo "$(tput setaf 3)$(tput blink)Now Creating Image, Please wait...$(tput sgr0)"
cp -rp /nfs/westpac/* .
echo
  echo "$(tput setaf 4)Image has been built on Server$(tput sgr0)"
  sleep 2s
  echo
  echo "$(tput setaf 5)Image building succesfull - please shutdown the pi after logging back in to complete network boot setup!$(tput sgr0)"
  echo "/nfs/$1 *(rw,sync,no_subtree_check,no_root_squash)" >> /etc/exports
  exportfs -r
sleep 2s
else
echo
  echo "$(tput setaf 1)$(tput blink)Image exists...qutting!$(tput sgr0)"
echo
sleep 2s
fi
exit 0
exit 0
}

function imageremove {
echo "Your Device Identity is $(tput setaf 1)$(tput bold)$1$(tput sgr0)"
if [ -d /tftpboot/$1 ]; then
echo
  echo "$(tput setaf 1)$(tput blink)Image exists...Removing it!$(tput sgr0)"
  exportfs -u *:/nfs/$1
sed -i /$1/d /etc/exports
rm -fr /tftpboot/$1
  rm -fr /nfs/$1
  exportfs -r
echo
echo "$(tput setaf 2)Image has been removed sucessfully...Bye!$(tput sgr0)"
echo
sleep 2s
  else
echo
  echo "$(tput setaf 1)$(tput blink)Image doesnt exists...Quitting!$(tput sgr0)"
sleep 2s
sed -i /$1/d /etc/exports
exportfs -r
echo
  fi
exit 0
}

sn[0]=$(tail -1 /proc/cpuinfo | grep -o ".\{8\}$")
IP=$(hostname -I)
echo
echo "$(tput setaf 1)$(tput bold)Welcome to Pi Nework boot creator...$(tput sgr0)"
echo
CHECK=$(vcgencmd otp_dump | grep 17:)

if [[ "$CHECK" == "17:3020000a" ]]; then
  echo "Boot mode fine :) ($CHECK)"
else
  echo "!!! Boot mode failed, value: $CHECK"
fi
read -e -p "Enter the Remote TFTP server IP...: " serverip
echo
echo 'Please enter your choice: '
echo

options=("Create Image on Server and Reboot" "Just reboot" "Shutdown" "Remove Image from Server" "Check firmware" "Update Firmware to enable Network Boot" "Quit")
select opt in "${options[@]}"
do
    case $opt in
        "Create Image on Server and Reboot")
            echo
    echo "You chose Option 1 ($(tput setaf 5)Please Wait - Loading you details to server$(tput sgr0))"
    index=$(printf "%1s"$sn)
    sshpass -p 'qwe' ssh -t -t -o StrictHostKeyChecking=no root@$serverip "`declare -f imagemaker`; imagemaker "$index" "$IP""
    sudo reboot
    break;;
        "Just reboot")
    echo
            echo "You chose Option 2"
            sudo reboot
            break;;
        "Shutdown")
    echo
            echo "You chose $REPLY which is $opt"
            sudo shutdown now
    break;;
        "Remove Image from Server")
    echo
    index1=$(printf "%1s"$sn)
    sshpass -p 'qwe' ssh -t -t -o StrictHostKeyChecking=no root@$serverip "`declare -f imageremove`; imageremove "$index1""
    ;;
        "Check firmware")
    echo
    CHECK=$(vcgencmd otp_dump | grep 17:)
    if [[ "$CHECK" == "17:3020000a" ]]; then
      echo "Boot mode fine :) ($CHECK)"
    else
      echo "!!! Boot mode failed, value: $CHECK"
    fi
    ;;
        "Update Firmware to enable Network Boot")
    echo
            echo "You chose $REPLY which is $opt"
    sudo apt-get install rpi-update && sudo rpi-update
    ;;
        "Quit")
            break
            ;;
        *) echo "invalid option $REPLY";;
    esac
done