#!/bin/sh # $FiG: config/freebsd/builder01/root/bin/create-and-populate-new-BE.sh,v 1.7 2018-07-30 06:52:11 trond Exp $ # $BSDnet: config/freebsd/enterprise/root/bin/create-and-populate-new-BE.sh,v 1.3 2018-07-30 08:17:53 trond Exp $ #set -x set -o pipefail # Specify which kernel to install. #KERNCONF=GENERIC #KERNCONF=ENTERPRISE KERNCONF=`sysctl -n kern.ident` # Specify where to place the typescripts. TYPESCRIPT_DIR=/mnt/root/tmp #TYPESCRIPT_DIR=/usr/src #TYPESCRIPT_DIR=/var/log/buildlog # Specify where the bootpool BE is mounted, typically /bootpool. BOOTPOOL_ROOT=/bootpool # Specify where to temporary mount the new BEs, typically /mnt. DESTDIR=/mnt # Determine a suitable git executable. GIT_CANDIDATES="/usr/local/bin/git /usr/bin/git /usr/bin/gitlite" for cand in ${GIT_CANDIDATES}; do if [ -x ${cand} ]; then GIT=${cand} break fi done if [ -z "${GIT}" ]; then echo "${0}: neither of ${GIT_CANDIDATES} are useable" >/dev/stderr exit 69 fi # Ensure / is of type ZFS. if [ -z "`/bin/df -Tt zfs /`" ]; then echo "${0}: root filesystem must be of type ZFS" >/dev/stderr exit 69 fi # Ensure ${BOOTPOOL_ROOT}/boot/loader.conf exists. if [ ! -f ${BOOTPOOL_ROOT}/boot/loader.conf ]; then echo "${0}: ${BOOTPOOL_ROOT}/boot/loader.conf does not exist" >/dev/stderr exit 69 fi # Ensure /usr/src is mounted, be it NFS or local fs. if [ ! -f /usr/src/Makefile ]; then /sbin/mount /usr/src if [ ! -f /usr/src/Makefile ]; then echo "${0}: unable to mount /usr/src" >/dev/stderr exit 69 fi fi # Ensure /usr/obj is mounted, be it NFS or local fs. if [ ! -d /usr/obj/usr ]; then /sbin/mount /usr/obj if [ ! -d /usr/obj/usr ]; then echo "${0}: unable to mount /usr/obj" >/dev/stderr exit 69 fi fi # What's the name of the current boot pool BE? CURRENT_BOOTPOOL_BE=`/bin/df ${BOOTPOOL_ROOT} | /usr/bin/tail -1 | /usr/bin/awk '{print $1}'` if [ -z "${CURRENT_BOOTPOOL_BE}" ]; then echo "${0}: zero length CURRENT_BOOTPOOL_BE" >/dev/stderr exit 69 fi # What's the name of the current root pool BE? CURRENT_ROOTPOOL_BE=`/bin/df / | /usr/bin/tail -1 | /usr/bin/awk '{print $1}'` if [ -z "${CURRENT_ROOTPOOL_BE}" ]; then echo "${0}: zero length CURRENT_ROOTPOOL_BE" >/dev/stderr exit 69 fi # What's the current timestamp given local time? CURRENT_TIMESTAMP=`/bin/date +%Y%m%d-%H%M%S` if [ -z "${CURRENT_TIMESTAMP}" ]; then echo "${0}: zero length CURRENT_TIMESTAMP" >/dev/stderr exit 69 fi # What's the Git commit count and the latest Git commit hash? echo "Inquiring Git about branch name, commit count, and latest commit hash ..." GIT_BRANCH=`${GIT} -C /usr/src rev-parse --abbrev-ref HEAD | sed 's|[/+]|-|g'` GIT_COMMIT_COUNT=`${GIT} -C /usr/src rev-list --first-parent --count HEAD` GIT_SHORT_COMMIT_HASH=`${GIT} -C /usr/src rev-parse --verify --short=12 HEAD` echo "... done" # Construct the new identification. NEW_ID="${CURRENT_TIMESTAMP}-${GIT_BRANCH}-n${GIT_COMMIT_COUNT}-${GIT_SHORT_COMMIT_HASH}" # Construct the name of the root pool snapshot. NEW_SNAPSHOT="${CURRENT_ROOTPOOL_BE}@${NEW_ID}" # Construct the name of the boot pool snapshot. NEW_BOOTPOOL_SNAPSHOT="${CURRENT_BOOTPOOL_BE}@${NEW_ID}" # Get the root of the boot pool BEs. BOOTPOOL_BE_ROOT=`/usr/bin/dirname ${CURRENT_BOOTPOOL_BE}` if [ -z "${BOOTPOOL_BE_ROOT}" ]; then echo "${0}: zero length BOOTPOOL_BE_ROOT" >/dev/stderr exit 69 fi # Get the name of the boot pool. BOOT_POOL=`echo "${BOOTPOOL_BE_ROOT}" | /usr/bin/cut -d / -f 1` if [ -z "${BOOT_POOL}" ]; then echo "${0}: zero length BOOT_POOL" >/dev/stderr exit 69 fi # Construct the name of the new boot pool BE. NEW_BOOTPOOL_BE="${BOOTPOOL_BE_ROOT}/${NEW_ID}" # Construct the name of the root pool snapshot. NEW_ROOTPOOL_SNAPSHOT="${CURRENT_ROOTPOOL_BE}@${NEW_ID}" # Get the root of the root pool BEs. ROOTPOOL_BE_ROOT=`/usr/bin/dirname ${CURRENT_ROOTPOOL_BE}` if [ -z "${ROOTPOOL_BE_ROOT}" ]; then echo "${0}: zero length ROOTPOOL_BE_ROOT" >/dev/stderr exit 69 fi # Get the name of the root pool. ROOT_POOL=`echo "${ROOTPOOL_BE_ROOT}" | /usr/bin/cut -d / -f 1` if [ -z "${ROOT_POOL}" ]; then echo "${0}: zero length ROOT_POOL" >/dev/stderr exit 69 fi # Construct the name of the new root pool BE. NEW_ROOTPOOL_BE="${ROOTPOOL_BE_ROOT}/${NEW_ID}" # Run pre-flight checks. This is an interactive step. #/usr/sbin/mergemaster -Fp || exit if [ ! -d /var/db/etcupdate/current ]; then /usr/sbin/etcupdate extract || exit if [ ! -d /var/db/etcupdate/current ]; then echo "${0}: unable to run etcupdate(8), missing directory /var/db/etcupdate/current" >/dev/stderr exit 69 fi fi echo "Running pre-flight checks using etcupdate(8) ..." /usr/sbin/etcupdate -p || exit /usr/sbin/etcupdate resolve -p || exit echo "... done." # Create the root pool snapshot and the new root pool BE. /sbin/zfs snapshot ${NEW_ROOTPOOL_SNAPSHOT} || exit /sbin/zfs clone -o mountpoint=${DESTDIR} ${NEW_ROOTPOOL_SNAPSHOT} ${NEW_ROOTPOOL_BE} || exit # Create the boot pool snapshot and the new boot pool BE. /sbin/zfs snapshot ${NEW_BOOTPOOL_SNAPSHOT} || exit /sbin/zfs clone -o mountpoint=${DESTDIR}${BOOTPOOL_ROOT} ${NEW_BOOTPOOL_SNAPSHOT} ${NEW_BOOTPOOL_BE} || exit # Update vfs.root.mountfrom in ${DESTDIR}${BOOTPOOL_ROOT}/boot/loader.conf to point to the new root pool BE. /usr/bin/sed -i '' "s|^vfs\\.root\\.mountfrom=\".*\"\$|vfs.root.mountfrom=\"zfs:${NEW_ROOTPOOL_BE}\"|" ${DESTDIR}${BOOTPOOL_ROOT}/boot/loader.conf || exit # Merge any changes to the configuration files. This is an interactive step. #/usr/sbin/mergemaster -D ${DESTDIR} -Fi || exit echo "Merging changes to configuration files using etcupdate(8) ..." /usr/sbin/etcupdate -D ${DESTDIR} -d /var/db/etcupdate || exit /usr/sbin/etcupdate resolve -D ${DESTDIR} -d /var/db/etcupdate || exit while /usr/sbin/etcupdate status -D ${DESTDIR} -d /var/db/etcupdate | grep -q '^ C'; do /usr/sbin/etcupdate resolve -D ${DESTDIR} -d /var/db/etcupdate || exit done echo "... done." # Ensure we have somewhere to place the typescripts. if [ ! -d ${TYPESCRIPT_DIR} ]; then /bin/mkdir -p ${TYPESCRIPT_DIR} if [ ! -d ${TYPESCRIPT_DIR} ]; then echo "${0}: unable to create ${TYPESCRIPT_DIR}" >/dev/stderr exit 69 fi fi # Remove previous typescripts. /bin/rm -f -- ${TYPESCRIPT_DIR}/make-installworld-installkernel-*.txt ${TYPESCRIPT_DIR}/make-check-old-*.txt ${TYPESCRIPT_DIR}/make-delete-old-*.txt # Install new world and kernel into the new BE. /usr/bin/script -at 0 ${TYPESCRIPT_DIR}/make-installworld-installkernel-${NEW_ID}.txt /usr/bin/make -C /usr/src -j `/sbin/sysctl -n hw.ncpu` DESTDIR=${DESTDIR} KERNCONF=${KERNCONF} installworld installkernel || exit # Check to see if there's something old and outdated. /usr/bin/script -at 0 ${TYPESCRIPT_DIR}/make-check-old-${NEW_ID}.txt /usr/bin/make -C /usr/src DESTDIR=${DESTDIR} check-old || exit # Remove any old files. /usr/bin/script -at 0 ${TYPESCRIPT_DIR}/make-delete-old-${NEW_ID}.txt /usr/bin/make -C /usr/src -D BATCH_DELETE_OLD_FILES DESTDIR=${DESTDIR} delete-old || exit # Remove any old libraries. /usr/bin/script -at 0 ${TYPESCRIPT_DIR}/make-delete-old-libs-${NEW_ID}.txt /usr/bin/make -C /usr/src -D BATCH_DELETE_OLD_FILES DESTDIR=${DESTDIR} delete-old-libs || exit # Check to see if there's still something old and outdated. /usr/bin/script -at 0 ${TYPESCRIPT_DIR}/make-check-old-${NEW_ID}.txt /usr/bin/make -C /usr/src DESTDIR=${DESTDIR} check-old || exit # Unmount the NFS mounted filesystems if needed. if [ "`/bin/df -T /usr/src | /usr/bin/tail -1 | /usr/bin/awk '{print $2}'`" = "nfs" ]; then /sbin/umount /usr/src || exit fi if [ "`/bin/df -T /usr/obj | /usr/bin/tail -1 | /usr/bin/awk '{print $2}'`" = "nfs" ]; then /sbin/umount /usr/obj || exit fi # Unconditionally remove any traces of any (false) NFS mounts. /bin/rm -f -- ${DESTDIR}/var/db/mounttab # Enable this if you have bemigrate.sh stored as /etc/rc.d/bemigrate # and also have set bemigrate_enable="YES" in /etc/rc.conf. # Place the /firstboot marker in the new BE. /usr/bin/touch ${DESTDIR}/firstboot # Inherit the mountpoint for the current boot pool BE. /sbin/zfs inherit mountpoint ${CURRENT_BOOTPOOL_BE} || exit # Update the mountpoint for the new boot pool BE. /sbin/zfs set mountpoint=${BOOTPOOL_ROOT} ${NEW_BOOTPOOL_BE} || exit # Set the bootfs zpool property on the boot pool. /sbin/zpool set bootfs=${NEW_BOOTPOOL_BE} ${BOOT_POOL} || exit # Inherit the mountpoint for the new root pool BE. /sbin/zfs inherit mountpoint ${NEW_ROOTPOOL_BE} || exit # Ready to reboot into the new boot pool BE. echo "${0}: ready to boot into ${NEW_BOOTPOOL_BE}" # EOF