• Recent
    • Unsolved
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    • Register
    • Login

    Ubuntu 20.04 NFS PXE autoinstall automation

    Scheduled Pinned Locked Moved
    Tutorials
    1
    1
    1.9k
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • F
      faboulous
      last edited by faboulous

      Here is a script to setup PXE boot for Ubuntu 20.04 server iso which can be preseed to automate server/desktop installation using cloud-init. It also automatically update fog pxe menu entry

      Since ubuntu 20, canonical deprecated debian-installer. Debian-installer is still working but I ran into issues with some statements and find out that using debian-installer successor cloud-init a bit easier to perform autoinstall.

      Ubuntu provide daily builds, we can use them to keep our iso updated by setting up a daily cronjob for this script and then add the user-data file needed as cloud-init input (inspired myself from this script which help greatly testing user-data file by wrapping it up into an ubuntu-server iso which can then be directly use either on vm or physical machine).

      #!/bin/bash
      
      DIST="ubuntu"
      RELEASE="focal"
      URL="https://cdimage.ubuntu.com/ubuntu-server/${RELEASE}/daily-live/current/${RELEASE}-live-server-amd64.iso"
      CHECKSUM_URL="https://cdimage.ubuntu.com/ubuntu-server/${RELEASE}/daily-live/current/SHA256SUMS"
      IMAGE_NAME="${DIST}/${RELEASE}"
      GIT_URL="https://some.git.repo.url/containing-user-data-file"
      
      # you need to setup an nfs server serving the NFS_DIR and a tftp server serving TFTP_DIR
      DOWNLOAD_DIR="/data/iso"
      TFTP_DIR="/tftpboot/os"
      NFS_DIR="/data/nfs"
      MOUNT_DIR="/media/tmp_image"
      NFS_SERVER_IP="your_fog_nfs_server_ip"
      
      # only define this if you have several vmlinuz or initrd inside the iso
      VMLINUZ=""
      INITRD=""
      
      # pxe parameters use in fog pxe menu entry 
      PXE_PARAMS="kernel tftp://\$\{fog-ip\}/os/${DIST}/${RELEASE}/vmlinuz
      initrd tftp://\$\{fog-ip\}/os/${DIST}/${RELEASE}/initrd
      imgargs boot=casper ip=dhcp netboot=nfs nfsroot=\$\{fog-ip\}:${NFS_DIR}/${IMAGE_NAME} rw"
      
      mkdir -p ${DOWNLOAD_DIR}/${DIST}/${RELEASE}
      image="${DOWNLOAD_DIR}/${DIST}/${RELEASE}/${RELEASE}-live-server-amd64.iso"
      
      function cleanup() {
              trap - SIGINT SIGTERM ERR EXIT
              if [ -n "${tmpdir+x}" ]; then
                      rm -rf "$tmpdir"
                      echo "🚽 Deleted temporary working directory $tmpdir"
              fi
      }
      
      trap cleanup SIGINT SIGTERM ERR EXIT
      
      testdir() {
        if [ ! -d "$1" ]; then
          echo "Directory $1 doesn't exist" 1>&2
          usage
          exit 1
        fi
      }
      
      checkIso() {
        if [ ! -f "${tmpdir}/SHA256SUMS-${today}" ]; then
          curl -NsSL ${CHECKSUM_URL} -o "${tmpdir}/SHA256SUMS-${today}"
        fi
        digest=$(sha256sum "${image}" | cut -f1 -d ' ')
        set +e
        grep -Fq "$digest" "${tmpdir}/SHA256SUMS-${today}"
        if [ $? -eq 0 ]; then
          echo "👍 Verification succeeded."
          set -e
          return 0
        else
          echo "👿 Verification of ISO digest failed." 1>&2;
          return 1
        fi
      }
      
      downloadIso() {
        if [ ! -f "${image}" ]; then
          echo "File $image doesn't exist, downloading iso"
          wget -P ${DOWNLOAD_DIR}/${DIST}/${RELEASE} ${URL}
        fi
        checkIso
        if [ $? -eq 1 ]; then
          rm ${image}
          downloadIso
        fi
      # TODO eventually check iso signature
      }
      
      # updating fog PXEMenu  
      updatePXEMenu() {
        echo "param $1 $2"
        pxeID=$(mysql --batch --skip-column-names --execute="select pxeID from fog.pxeMenu where pxeName=\"${DIST}_${RELEASE}_$1\"" | head -n 1)
        if [ -z "$pxeID"  ]; then
          echo "No entry for ${DIST} ${RELEASE} $1, generating a new one"
      
          mysql --batch --skip-column-names --execute="INSERT INTO fog.pxeMenu (pxeName, pxeDesc, pxeParams, pxeRegOnly, pxeArgs, pxeDefault, pxeHotKeyEnable, pxeKeySequence) VALUES (\"${DIST}_${RELEASE}_$1\", \"${DIST} ${RELEASE} $1 image\", '$2', 2, \"\", 0, \"0\", \"\");"
        else
          echo "Entry found for ${DIST} ${RELEASE}, updating"
          mysql --batch --skip-column-names --execute="UPDATE fog.pxeMenu SET pxeName=\"${DIST}_${RELEASE}_$1\", pxeDesc=\"${DIST} ${RELEASE} $1 image\", pxeParams='$2' where pxeID=${pxeID};"
        fi
      }
      
      # clone the git repo containing user-data files
      # it will search for user data store in /user-data/${DIST}/${RELEASE}/
      # you can them define as many user-data file as you want by creating storing 
      # them this way inside the repo : 
      # user-data/${DIST}/${RELEASE}/desktop-minimal/user-data
      # user-data/${DIST}/${RELEASE}/desktop-full/user-data 
      addUserData() {
        git clone --quiet ${GIT_URL} ${tmpdir}/cloud-init
        mkdir -p ${NFS_DIR}/${IMAGE_NAME}/nocloud
        cp -r ${tmpdir}/cloud-init/user-data/${DIST}/${RELEASE}/* ${NFS_DIR}/${IMAGE_NAME}/nocloud/
        for item in ${NFS_DIR}/${IMAGE_NAME}/nocloud/*; do
          item="$(echo $item | sed 's#.*/##')"
          tmp="${PXE_PARAMS} autoinstall ds=nocloud;s=/cdrom/nocloud/${item}"
          updatePXEMenu "autoinstall_${item}" "${tmp}"
        done
      }
      
      echo "PXE image script"
      if [ "$EUID" -ne 0 ]; then
        echo "Please run as root"
        exit
      fi
      
      tmpdir=$(mktemp -d)
      
      if [[ ! "$tmpdir" || ! -d "$tmpdir" ]]; then
              echo "💥 Could not create temporary working directory." 1>&2; exit 1;
      else
              echo "📁 Created temporary working directory $tmpdir"
      fi
      
      
      downloadIso
      mkdir -p ${MOUNT_DIR}
      echo "Trying to mount ${image} to ${MOUNT_DIR}..."
      mount -ro loop ${image} ${MOUNT_DIR}
      vmlinuzs=( $(find ${MOUNT_DIR} -name "vmlinuz*") )
      index=0
      nbelem=${#vmlinuzs[@]}
      if [ ${nbelem} -ne 1 ]; then
        echo "absent or multiple vmlinuz file, please run interactive script" 1>&2
        exit 1
      fi
      VMLINUZ=${vmlinuzs[${index}]}
      echo "The file ${VMLINUZ} will be used"
      initrds=( $(find ${MOUNT_DIR} -name "initrd*") )
      index=0
      nbelem=${#initrds[@]}
      if [ ${nbelem} -ne 1 ]; then
        echo "absent or multiple initrd file, please run interactive script" 1>&2
        exit 1
      fi
      INITRD=${initrds[${index}]}
      echo "The file ${INITRD} will be used"
      
      mkdir -vp ${TFTP_DIR}/${IMAGE_NAME}
      mkdir -vp ${NFS_DIR}/${IMAGE_NAME}
      echo "Copying the image file to NFS Server"
      cp -Rf ${MOUNT_DIR}/* ${NFS_DIR}/${IMAGE_NAME}
      # match hidden files too (store UUID needed to use NFS as it perform a check)
      cp -Rf ${MOUNT_DIR}/.[!.]* ${NFS_DIR}/${IMAGE_NAME}
      echo "Copying the vmlinuz & initrd files to TFTP Server"
      cp -f ${VMLINUZ} ${TFTP_DIR}/${IMAGE_NAME}/
      cp -f ${INITRD} ${TFTP_DIR}/${IMAGE_NAME}/
      umount ${MOUNT_DIR}
      
      echo "Editing TFTP config file"
      # setting up an entry with no autoinstall 
      updatePXEMenu "server" "${PXE_PARAMS}"
      # setting up one entry per user-data stored in your git repo 
      addUserData
      echo "Restarting TFTP Server"
      service tftpd-hpa restart
      echo "Finished"
      
      

      To setup manually this instead of using this script, you can follow this kind of instruction but perform the following command after this one cp -R /mnt/loop/* /images/os/mint/19.1

      cp -R /mnt/loop/.[!.]* /images/os/mint/19.1
      

      This script can be adapted to setup other distro iso (without automation as I think only ubuntu will work with cloud init)

      1 Reply Last reply Reply Quote 1
      • 1 / 1
      • First post
        Last post

      227

      Online

      12.1k

      Users

      17.3k

      Topics

      155.3k

      Posts
      Copyright © 2012-2024 FOG Project