Skip to content

Instantly share code, notes, and snippets.

@smcnamara3
Created March 25, 2016 07:54
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save smcnamara3/796e3357e029b8996c9f to your computer and use it in GitHub Desktop.
Save smcnamara3/796e3357e029b8996c9f to your computer and use it in GitHub Desktop.
ZFS root on Xenial - personal fork of http://pastebin.com/raw/fa83QrBk
#!/bin/bash
# ZFS-setup.sh 2016-03-24 19:42
# Auto-installer for clean new system using root on zfs, and optionally on
# luks encrypted disks. It installs Ubuntu 14.04.04 or 16.04 with everything
# needed to support ZFS and potentially LUKS. Without LUKS everything lives
# in the main rpool pool. With LUKS then /boot lives in its own boot pool.
# Grub2 is installed to all disks, so the system can boot cleanly from *any*
# disk, even with a failed disk.
# This script is meant to be run from an Ubuntu live-CD or a minimal
# install (from a usb key for example). It will create a list of all disks it
# can see then ask the user to edit that list if required. All disks listed
# in that ZFS-setup.disks.txt file will be wiped CLEAN for the install.
# It can copy the /etc/ssh directory from the build-host into the newly
# created system. Makes for *much* easier testing when running multiple times.
# Basic use from ubuntu-14.04.4-desktop-amd64.iso Live-CD
#
# Boot ISO, select "Try Ubuntu"
# Open terminal
# sudo -i
# wget http://<link> -O ZFS-setup.sh
# chmod +x ZFS-setup.sh
# nano ZFS-setup.sh
# set variables in ZFS-setup.sh - see below
# ./ZFS-setup.sh
# ctrl-C to exit at list of disks
# nano ZFS-setup.disks.txt
# Ensure list of disks is correct
# ./ZFS-setup.sh
# press <enter> to accept list of disks and swap size
# enter password for main userid
# enter password again
# press <enter> to accept final disk layout
# It will create a few scripts - seen as the "cat > /path/script.sh << EOF" below.
# Setup.sh : Goes in /root of the new system, and is used to build/install
# : the rest of the system after debootstrap.
# Reboot-testing.sh : Goes in the local build-host /root, and is used for
# : entering/exiting the new system via chroot for debugging.
# Replace-failed-drive.sh : Goes in /root of new system, used to replace a failed drive.
# : NOTE - incomplete
# The following stock files are modified
#
# /usr/share/initramfs-tools/scripts/local-top/cryptroot (if using LUKS)
# /etc/default/grub
# /etc/default/locale
# /etc/crypttab (if using LUKS)
# /etc/modules
# /etc/timezone
# /etc/localtime
# /etc/hostname
# /etc/hosts
# /etc/fstab
# /etc/bash.bashrc
# /etc/skel/.bashrc
# /etc/network/interfaces
# /etc/apt/sources.list
# /etc/mdadm/mdadm.conf (if using LUKS)
# /etc/initramfs-tools/conf.d/resume
# The following new files are created
#
# /root/.ssh/authorized_keys
# /etc/udev/rules.d/99-local-crypt.rules (if using LUKS)
# /etc/udev/rules.d/61-zfs-vdev.rules
# /etc/apt/apt.conf.d/03proxy (if proxy is defined)
# /etc/apt/apt.conf.d/02periodic
# /etc/sudoers.d/zfsALLOW
# /etc/initramfs-tools/modules
# /etc/initramfs-tools/scripts/luks/get.root_crypt.decrypt_derived (if using LUKS)
# /etc/initramfs-tools/conf.d/cryptroot (if using LUKS)
# /etc/initramfs-tools/conf.d/dropbear_network (if using LUKS)
# /etc/initramfs-tools/hooks/mount_cryptroot (if using LUKS)
# /etc/initramfs-tools/hooks/busybox2 (if using LUKS)
# /etc/initramfs-tools/hooks/dropbear.fixup2 (if using LUKS)
# /etc/initramfs-tools/root/.ssh/authorized_keys (if using LUKS)
# /usr/share/initramfs-tools/conf-hooks.d/forcecryptsetup (if using LUKS)
# /etc/initramfs-tools/scripts/init-premount/zzmdraidforce (if using LUKS)
# /etc/initramfs-tools/scripts/init-premount/network-down
# FIXMEs
#
# - 16.04/xenial now uses new systemd device naming, so eth0 becomes enp0s3 or similar.
# So /etc/initramfs-tools/scripts/init-premount/network-down must be customized, or we
# must put net.ifnames=0 on the grub cmdline to use old eth0 style network names rather
# than the newer enp3s0 type. Search below for GRUB_CMDLINE_LINUX_DEFAULT
# -------Set the following variables ---------------------------------------------------------------
# Which version of Ubuntu to install trusty=14.04 xenial=16.04
SUITE=xenial
# Userid to create in new system
USERNAME=zuser
# SSH pubkey to add to new system
SSHPUBKEY="ssh-rsa ABCDE= Johnny Bravo"
# System name (also used for mdadm raid set names and filesystem LABELs)
# Note: Only first 10 chars of name will be used for LABELs
SYSNAME=installerbox
# Using LUKS for encryption ? Please use a nice long complicated passphrase (y/n)
# If enabled, will encrypt partition_swap (md raid) and partition_data (zfs)
LUKS=
PASSPHRASE=password
# Zero/randomize out the disks for LUKS ? (y/n)
ZERO=
# Using a proxy like apt-cacher-ng ?
# PROXY=
# zpool raid level to use for more than 2 disks - raidz, raidz2, raidz3, mirror
# For 2 disks, will be forced to mirror
ZPOOLEVEL=mirror
# Copy the build-host /etc/ssh into the newly created system ?
COPY_SSH=y
# Are we configuring to use UEFI ?
UEFI=y
# Force the swap partition size for each disk in MB if you don't want it calculated
# If you want Resume to work, total swap must be > total ram
# Set to 0 to disable (SIZE_SWAP = swap partitions, SIZE_ZVOL = zfs zvol in rpool)
SIZE_SWAP=0
SIZE_ZVOL=32768
# Use zswap compressed page cache in front of swap ? https://wiki.archlinux.org/index.php/Zswap
USE_ZSWAP="\"zswap.enabled=1 zswap.compressor=lz4 zswap.max_pool_percent=25\""
# USE_ZSWAP=
# Set the source of debootstrap - can be a local repo built with apt-move
DEBOOTSTRAP="http://us.archive.ubuntu.com/ubuntu/"
# DEBOOTSTRAP="file:///root/UBUNTU"
# Generic partition setup as follows
# sdX1 : EFI boot
# sdX2 : Grub boot
# sdX3 : /boot (only used for LUKS)
# sdX4 : swap
# sdX5 : main ZFS partition
# sdX9 : ZFS reserved
# Partition numbers and sizes of each partition in MB
PARTITION_EFI=1
SIZE_EFI=100
PARTITION_GRUB=2
SIZE_GRUB=2
PARTITION_BOOT=3
SIZE_BOOT=500
PARTITION_SWAP=4
PARTITION_DATA=5
PARTITION_RSVD=9
# ------ End of user settable variables ------------------------------------------------------------
if [[ $EUID -ne 0 ]]; then
echo "This script must be run as root" 1>&2
exit 1
fi
BOXNAME=${SYSNAME:0:10}
if [ ${#SYSNAME} -gt 10 ]; then
echo "$(tput setaf 1)!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!$(tput sgr0)"
echo "$(tput setaf 1)!!$(tput sgr0)"
echo "$(tput setaf 1)!!$(tput setaf 6) ${SYSNAME}$(tput sgr0) is too long - must be 10 chars max"
echo "$(tput setaf 1)!!$(tput sgr0) Will use $(tput setaf 6)${BOXNAME}$(tput sgr0) in labels"
echo "$(tput setaf 1)!!$(tput sgr0)"
echo "$(tput setaf 1)!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!$(tput sgr0)"
echo "$(tput setaf 3) Press <enter> to continue, or ctrl-C to abort $(tput setaf 1)"
read QUIT
echo ""
fi
# Generate (if necessary) list of disks and ask user below if it's good to go
[ ! -e /root/ZFS-setup.disks.txt ] && for disk in `ls -l /dev/disk/by-id | egrep -v '(-part|md-|dm-)' | sort -t '/' -k3 | tr -s " " | cut -d' ' -f9`; do echo $disk >> /root/ZFS-setup.disks.txt; done
i=1
for disk in `cat /root/ZFS-setup.disks.txt` ; do
DISKS[$i]=$disk
i=$(($i+1))
done
# Calculate proper SWAP size (if not defined above) - should be same size as total RAM in system
MEMTOTAL=`cat /proc/meminfo | fgrep MemTotal | tr -s ' ' | cut -d' ' -f2`
[ ${SIZE_SWAP} ] || SIZE_SWAP=$(( ${MEMTOTAL} / ${#DISKS[@]} / 1024 ))
echo "$(tput setaf 1)!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
echo "$(tput setaf 1)!!"
echo "$(tput setaf 1)!!$(tput sgr0) These are the disks we're about for $(tput setaf 1)FORMAT$(tput sgr0) for ZFS"
echo "$(tput setaf 1)!!"
i=1
for disk in `seq 1 ${#DISKS[@]}` ; do
echo "$(tput setaf 1)!!$(tput sgr0) disk $i = ${DISKS[$i]} (`readlink /dev/disk/by-id/${DISKS[$i]} | cut -d/ -f3`)"
i=$(($i+1))
done
echo "$(tput setaf 1)!!"
echo "$(tput setaf 1)!!$(tput sgr0) Be $(tput setaf 1)SURE$(tput sgr0), really $(tput setaf 1)SURE$(tput sgr0), as they will be wiped completely"
echo "$(tput setaf 1)!!$(tput sgr0) Otherwise abort and edit the $(tput setaf 6)/root/ZFS-setup.disks.txt$(tput sgr0) file"
echo "$(tput setaf 1)!!"
if [ ${SIZE_SWAP} != 0 ]; then
if [ ${#DISKS[@]} -gt 2 ]; then
# raid10 size
SIZE_SWAP_TOTAL=$(( ${SIZE_SWAP} * ${#DISKS[@]} / 2 ))
else
# raid1 mirror size
SIZE_SWAP_TOTAL=$(( ${SIZE_SWAP} * ${#DISKS[@]} ))
fi
echo "$(tput setaf 1)!!$(tput sgr0) ${#DISKS[@]} SWAP partitions of ${SIZE_SWAP}MB = $(( ${SIZE_SWAP_TOTAL} / 1024 ))GB = ${SIZE_SWAP_TOTAL}MB total"
echo -n "$(tput setaf 1)!!$(tput sgr0) Ram = ${MEMTOTAL}kb Swap partitions $(tput setaf 3)"
if [ ${#DISKS[@]} -gt 2 ]; then
echo -n "raid10"
else
echo -n "raid1"
fi
echo " $(tput sgr0)= $(( ${SIZE_SWAP_TOTAL} * 1024 ))kb "
# Say whether resume is possible
if [ ${MEMTOTAL} -gt $(( ${SIZE_SWAP_TOTAL} * 1024 )) ] ; then
SWAPRESUME=n
echo "$(tput setaf 1)!!$(tput sgr0) Hibernate/Resume $(tput setaf 1)NOT$(tput sgr0) possible"
else
SWAPRESUME=y
echo "$(tput setaf 1)!!$(tput sgr0) Hibernate/Resume $(tput setaf 6)IS$(tput sgr0) possible"
fi
echo "$(tput setaf 1)!!$(tput sgr0) Edit $(tput setaf 6)/root/ZFS-setup.sh$(tput sgr0) to force the swap partition size with SIZE_SWAP"
echo "$(tput setaf 1)!!$(tput sgr0) NOTE: If only 2 disks -> swap partitions are raid1/mirrored."
echo "$(tput setaf 1)!!$(tput sgr0) More than 2 disks -> swap partitions are raid10."
echo "$(tput setaf 1)!!"
fi
echo "$(tput setaf 1)!!!!!!!!$(tput setaf 3) Press <enter> to continue, or ctrl-C to abort $(tput setaf 1)!!!!!!!!!!!!!!!!!!!!!"
read QUIT
# Input USERNAME password for main id
DONE=false
until ${DONE} ; do
echo ""
echo "$(tput sgr0)Please enter password for $(tput setaf 3)${USERNAME}$(tput sgr0) in new system"
read -s -p "Password: " PASSWORD1
echo ""
read -s -p "Password again: " PASSWORD2
[ ${PASSWORD1} = ${PASSWORD2} ] && DONE=true
done
echo ""
UPASSWORD=${PASSWORD1}
# Log everything we do
rm -f /root/ZFS-setup.log
exec > >(tee -a "/root/ZFS-setup.log") 2>&1
# Proxy
if [ ${PROXY} ]; then
# These are for debootstrap
export http_proxy=${PROXY}
export ftp_proxy=${PROXY}
# This is for apt-get
echo 'Acquire::http::proxy "${PROXY}";' > /etc/apt/apt.conf.d/03proxy
fi
# Make sure we have utilities we need
if [ ! -e /sbin/zpool ]; then
apt-add-repository --yes ppa:zfs-native/stable
echo "--- apt-get update"
apt-get update > /dev/null
apt-get -y --no-install-recommends install ubuntu-zfs
fi
modprobe zfs
for UTIL in /sbin/{mdadm,gdisk,cryptsetup} /usr/sbin/debootstrap ; do
[ ! -e ${UTIL} ] && apt-get -y --no-install-recommends install `basename ${UTIL}`
done
# For more packages whose name doesn't match the executable, use this method
#
# UTIL_FILE[0]=/sbin/mdadm ; UTIL_PKG[0]=mdadm
# UTIL_FILE[1]=/sbin/gdisk ; UTIL_PKG[1]=gdisk
# UTIL_FILE[3]=/usr/sbin/debootstrap ; UTIL_PKG[2]=debootstrap
# UTIL_FILE[4]=/usr/sbin/sshd ; UTIL_PKG[4]=openssh-server
# for UTIL in `seq 0 ${#UTIL_FILE[@]}` ; do
# UTIL_INSTALL="${UTIL_INSTALL} ${UTIL_PKG[${UTIL}]}"
# done
# apt-get -y --no-install-recommends install ${UTIL_INSTALL}
# Unmount any mdadm disks that might have been automounted
umount /dev/md* > /dev/null 2>&1
# Stop all found mdadm arrays
mdadm --stop --force /dev/md* > /dev/null 2>&1
# Zero entire disk if requested
if [ "ZZ${ZERO}" = "ZZy" ]; then
echo "-----------------------------------------------------------------------------"
echo "Fetching frandom kernel module"
# urandom is limited, so use frandom module
[ ! -e /var/lib/dpkg/info/build-essential.list ] && apt-get -y install build-essential
mkdir -p /usr/src/frandom
wget --no-proxy http://billauer.co.il/download/frandom-1.1.tar.gz -O /usr/src/frandom/frandom-1.1.tar.gz
cd /usr/src/frandom
tar xvzf frandom-1.1.tar.gz
cd frandom-1.1
make
install -m 644 frandom.ko /lib/modules/`uname -r`/kernel/drivers/char/
depmod -a
modprobe frandom
for DISK in `seq 1 ${#DISKS[@]}` ; do
echo "Zeroing ${DISKS[${DISK}]}"
dd if=/dev/frandom of=/dev/disk/by-id/${DISKS[${DISK}]} bs=512 count=$(blockdev --getsz /dev/disk/by-id/${DISKS[${DISK}]}) &
WAITPIDS="${WAITPIDS} "$!
done
# USR1 dumps status of dd, this will take around 6 hours for 3TB SATA disk
# killall -USR1 dd
echo "Waiting for disk zeroing to finish"
wait ${WAITPIDS}
fi
echo "-----------------------------------------------------------------------------"
echo "Clearing out md raid, zpool and LUKS info from disks"
for DISK in `seq 1 ${#DISKS[@]}` ; do
echo ">>>>> ${DISKS[${DISK}]}"
# wipe it out ...
wipefs -a /dev/disk/by-id/${DISKS[${DISK}]}
# Clear any old zpool info
zpool labelclear -f /dev/disk/by-id/${DISKS[${DISK}]} > /dev/null 2>&1
[ -e /dev/disk/by-id/${DISKS[${DISK}]}-part${PARTITION_DATA} ] && zpool labelclear -f /dev/disk/by-id/${DISKS[${DISK}]}-part${PARTITION_DATA} > /dev/null 2>&1
# Wipe mdadm superblock from all partitions found, even if not md raid partition
mdadm --zero-superblock --force /dev/disk/by-id/${DISKS[${DISK}]} > /dev/null 2>&1
[ -e /dev/disk/by-id/${DISKS[${DISK}]}-part${PARTITION_BOOT} ] && mdadm --zero-superblock --force /dev/disk/by-id/${DISKS[${DISK}]}-part${PARTITION_BOOT} > /dev/null 2>&1
[ -e /dev/disk/by-id/${DISKS[${DISK}]}-part${PARTITION_SWAP} ] && mdadm --zero-superblock --force /dev/disk/by-id/${DISKS[${DISK}]}-part${PARTITION_SWAP} > /dev/null 2>&1
[ -e /dev/disk/by-id/${DISKS[${DISK}]}-part${PARTITION_RSVD} ] && mdadm --zero-superblock --force /dev/disk/by-id/${DISKS[${DISK}]}-part${PARTITION_RSVD} > /dev/null 2>&1
# Clear any old LUKS or mdadm info
[ -e /dev/disk/by-id/${DISKS[${DISK}]}-part${PARTITION_DATA} ] && dd if=/dev/zero of=/dev/disk/by-id/${DISKS[${DISK}]}-part${PARTITION_DATA} bs=512 count=20480 > /dev/null 2>&1
[ -e /dev/disk/by-id/${DISKS[${DISK}]}-part${PARTITION_SWAP} ] && dd if=/dev/zero of=/dev/disk/by-id/${DISKS[${DISK}]}-part${PARTITION_SWAP} bs=512 count=20480 > /dev/null 2>&1
[ -e /dev/disk/by-id/${DISKS[${DISK}]}-part${PARTITION_RSVD} ] && dd if=/dev/zero of=/dev/disk/by-id/${DISKS[${DISK}]}-part${PARTITION_RSVD} bs=512 count=4096 > /dev/null 2>&1
# Zero old MBR and GPT partition information on disks
sgdisk -Z /dev/disk/by-id/${DISKS[${DISK}]}
# Create new GPT partition label on disks
parted -s -a optimal /dev/disk/by-id/${DISKS[${DISK}]} mklabel gpt
# Rescan partitions
partprobe /dev/disk/by-id/${DISKS[${DISK}]}
if [ "ZZ${UEFI}" = "ZZy" ]; then
sgdisk -n1:2048:+256M -t1:EF00 -c1:"EFI_${DISK}" /dev/disk/by-id/${DISKS[${DISK}]}
fi
sgdisk -n2:0:+5M -t2:EF02 -c2:"GRUB_${DISK}" /dev/disk/by-id/${DISKS[${DISK}]}
if [ "ZZ${LUKS}" = "ZZy" ]; then
sgdisk -n3:0:+${SIZE_BOOT}M -t3:FD00 -c3:"BOOT_${DISK}" /dev/disk/by-id/${DISKS[${DISK}]}
fi
if [ ${SIZE_SWAP} != 0 ]; then
sgdisk -n4:0:+${SIZE_SWAP}M -t4:FD00 -c4:"SWAP_${DISK}" /dev/disk/by-id/${DISKS[${DISK}]}
fi
sgdisk -n5:0:-8M -t5:BF01 -c5:"ZFS_${DISK}" /dev/disk/by-id/${DISKS[${DISK}]}
sgdisk -n9:0:0 -t9:BF07 -c9:"RSVD_${DISK}" /dev/disk/by-id/${DISKS[${DISK}]}
partprobe /dev/disk/by-id/${DISKS[${DISK}]}
echo ""
done
gdisk -l /dev/disk/by-id/${DISKS[1]}
# And, just to be sure, since sometimes stuff hangs around
# Unmount any mdadm disks that might have been automounted
umount /dev/md* > /dev/null 2>&1
# Stop all found mdadm arrays
mdadm --stop --force /dev/md* > /dev/null 2>&1
# Build list of partitions to use for ...
# Boot partition (mirror across all disks)
PARTSBOOT=
PARTSSWAP=
PARTSRSVD=
# ZFS partitions to create zpool with
ZPOOLDISK=
for DISK in `seq 1 ${#DISKS[@]}` ; do
PARTSSWAP="${PARTSSWAP} /dev/disk/by-id/${DISKS[${DISK}]}-part${PARTITION_SWAP}"
PARTSBOOT="${PARTSBOOT} /dev/disk/by-id/${DISKS[${DISK}]}-part${PARTITION_BOOT}"
if [ "ZZ${LUKS}" = "ZZy" ]; then
PARTSRSVD="${PARTSRSVD} /dev/disk/by-id/${DISKS[${DISK}]}-part${PARTITION_RSVD}"
ZPOOLDISK="${ZPOOLDISK} /dev/mapper/root_crypt${DISK}"
else
ZPOOLDISK="${ZPOOLDISK} /dev/disk/by-id/${DISKS[${DISK}]}-part${PARTITION_DATA}"
fi
done
# Pick raid level to use dependent on number of disks
# disks = 2 : zpool and swap use mirror
# disks > 2 : zpool use raidz, swap use raid10
if [ ${#DISKS[@]} = 2 ]; then
ZPOOLEVEL=mirror
SWAPRAID=raid1
else
# ZPOOLEVEL is left to whatever you chose at top vars list
SWAPRAID="raid10 -p f2"
fi
echo "-----------------------------------------------------------------------------"
# Create raid for swap if SIZE_SWAP defined (use -p f2 for raid10)
if [ ${SIZE_SWAP} != 0 ]; then
echo "Creating ${BOXNAME}:swap raid0 for new system"
echo y | mdadm --create /dev/md/${BOXNAME}:swap --metadata=1.0 --force --level=${SWAPRAID} --raid-device=${#DISKS[@]} --homehost=${BOXNAME} --name=swap --assume-clean ${PARTSSWAP}
fi
# Format EFI System Partitions on both disks as FAT32
if [ "ZZ${UEFI}" = "ZZy" ]; then
echo "Formatting EFI system partitions"
for DISK in `seq 1 ${#DISKS[@]}` ; do
echo "${DISKS[${DISK}]}-part${PARTITION_EFI}"
mkfs.vfat -v -F32 -s2 -n "EFI_${DISK}" /dev/disk/by-id/${DISKS[${DISK}]}-part${PARTITION_EFI} > /dev/null 2>&1
done
fi
# Create LUKS devices if LUKS enabled
if [ "ZZ${LUKS}" = "ZZy" ]; then
echo "-----------------------------------------------------------------------------"
if [ ${SIZE_SWAP} != 0 ]; then
# Create encrypted swap on top of md raid array
echo "Encrypting SWAP ${BOXNAME}:swap"
echo ${PASSPHRASE} | cryptsetup --batch-mode luksFormat -c aes-xts-plain64 -s 512 -h sha512 /dev/md/${BOXNAME}:swap
echo ${PASSPHRASE} | cryptsetup luksOpen /dev/md/${BOXNAME}:swap ${BOXNAME}:swap
ln -sf /dev/mapper/${BOXNAME}:swap /dev/${BOXNAME}:swap
fi
# Create encrypted rsvd on top of md array - used as main key for other encrypted
echo "Creating ${BOXNAME}:rsvd raid0 for new system"
echo y | mdadm --create /dev/md/${BOXNAME}:rsvd --metadata=1.0 --force --level=raid1 --raid-device=${#DISKS[@]} --homehost=${BOXNAME} --name=rsvd ${PARTSRSVD}
echo ${PASSPHRASE} | cryptsetup --batch-mode luksFormat -c aes-xts-plain64 -s 512 -h sha512 /dev/md/${BOXNAME}:rsvd
echo ${PASSPHRASE} | cryptsetup luksOpen /dev/md/${BOXNAME}:rsvd ${BOXNAME}:rsvd
ln -sf /dev/mapper/${BOXNAME}:rsvd /dev
# Get derived key and insert into other encrypted devices
/lib/cryptsetup/scripts/decrypt_derived ${BOXNAME}:rsvd > /tmp/key
if [ ${SIZE_SWAP} != 0 ]; then
echo ${PASSPHRASE} | cryptsetup luksAddKey /dev/md/${BOXNAME}:swap /tmp/key
fi
# Create encrypted ZFS source partitions
for DISK in `seq 1 ${#DISKS[@]}` ; do
echo "Encrypting ZFS partition ${DISKS[${DISK}]}-part${PARTITION_DATA}"
echo ${PASSPHRASE} | cryptsetup --batch-mode luksFormat -c aes-xts-plain64 -s 512 -h sha512 /dev/disk/by-id/${DISKS[${DISK}]}-part${PARTITION_DATA}
echo ${PASSPHRASE} | cryptsetup luksOpen /dev/disk/by-id/${DISKS[${DISK}]}-part${PARTITION_DATA} root_crypt${DISK}
ln -sf /dev/mapper/root_crypt${DISK} /dev/root_crypt${DISK}
# Insert derived key
echo ${PASSPHRASE} | cryptsetup luksAddKey /dev/disk/by-id/${DISKS[${DISK}]}-part${PARTITION_DATA} /tmp/key
# Backup LUKS headers for ZFS partitions
cryptsetup luksHeaderBackup /dev/disk/by-id/${DISKS[${DISK}]}-part${PARTITION_DATA} --header-backup-file /root/LUKS-header-backup-${DISKS[${DISK}]}-part${PARTITION_DATA}.img
done
fi # LUKS
# Really, REALLY ugly hack to accomodate update-grub
for DISK in `seq 1 ${#DISKS[@]}` ; do
# Only create DATA partition link if *not* using LUKS
[ "ZZ${LUKS}" = "ZZ" ] && ln -sf /dev/disk/by-id/${DISKS[${DISK}]}-part${PARTITION_DATA} /dev
ln -sf /dev/disk/by-id/${DISKS[${DISK}]}-part${PARTITION_BOOT} /dev
done
echo "-----------------------------------------------------------------------------"
if [ "ZZ${LUKS}" = "ZZy" ]; then
echo "Creating /boot ZFS raidz/mirror for new system"
# For creating a /boot pool use -o version=28
#zpool create -f -o ashift=12 -o cachefile= -o version=28 \
# -O atime=off -O canmount=off -O compression=zle -m none \
# boot ${ZPOOLEVEL} ${PARTSBOOT}
zpool create -f -o ashift=12 -m none \
-d \
-o feature@async_destroy=enabled \
-o feature@empty_bpobj=enabled \
-o feature@lz4_compress=enabled \
-o feature@spacemap_histogram=enabled \
-o feature@enabled_txg=enabled \
-O atime=off -O canmount=off -O compression=lz4 \
boot ${ZPOOLEVEL} ${PARTSBOOT}
zfs set com.sun:auto-snapshot=false boot
zpool export boot
fi # LUKS
# Create main zpool
zpool create -f -o ashift=12 \
-d \
-o feature@async_destroy=enabled \
-o feature@empty_bpobj=enabled \
-o feature@lz4_compress=enabled \
-o feature@spacemap_histogram=enabled \
-o feature@enabled_txg=enabled \
-O atime=off -O canmount=off -O compression=lz4 \
rpool ${ZPOOLEVEL} ${ZPOOLDISK}
zfs set mountpoint=/ rpool
# Mount rpool under /mnt/zfs to install system, clean /mnt/zfs first
zpool export rpool
rm -rf /mnt/zfs
if [ "ZZ${LUKS}" = "ZZy" ]; then
zpool import -d /dev/mapper -R /mnt/zfs rpool
else
zpool import -d /dev/disk/by-id -R /mnt/zfs rpool
fi
# No need to auto-snapshot the pool itself, though you have to explicitly set true for datasets
zfs set com.sun:auto-snapshot=false rpool
# Create container for root dataset
zfs create -o canmount=off -o mountpoint=none -o compression=lz4 -o atime=off rpool/ROOT
# Enable auto snapshots with zfs-auto-snapshot
zfs set com.sun:auto-snapshot=true rpool/ROOT
# Set threshold for zfs-auto-snapshot
zfs set com.sun:snapshot-threshold=2000000 rpool/ROOT
# Create root dataset to hold main filesystem
zfs create -o canmount=noauto -o mountpoint=/ -o compression=lz4 -o atime=off -o xattr=sa rpool/ROOT/ubuntu
zpool set bootfs=rpool/ROOT/ubuntu rpool
zfs mount rpool/ROOT/ubuntu
if [ "ZZ${LUKS}" = "ZZy" ]; then
zpool import -d /dev/disk/by-id -R /mnt/zfs boot
# Set up /boot filesystem and possibly for EFI
# Create container for boot dataset
### zfs create -o canmount=off -o mountpoint=none -o compression=zle -o atime=off boot/BOOT
# Create root dataset to hold boot filesystem
zfs create -o mountpoint=/boot -o compression=zle -o atime=off -o xattr=sa boot/ubuntu
# Enable auto snapshots with zfs-auto-snapshot
zfs set com.sun:auto-snapshot=true boot/ubuntu
# Set threshold for zfs-auto-snapshot
zfs set com.sun:snapshot-threshold=2000000 boot/ubuntu
fi
# Create swap in zfs
if [ ${SIZE_ZVOL} != 0 ]; then
zfs create -V ${SIZE_ZVOL}M -b $(getconf PAGESIZE) \
-o compression=zle \
-o primarycache=metadata \
-o secondarycache=none \
-o sync=always \
-o logbias=throughput \
-o com.sun:auto-snapshot=false rpool/SWAP
fi
echo "--------------------- $(tput setaf 1)About to debootstrap into /mnt/zfs$(tput sgr0) --------------------"
df -h
echo "--------------------- $(tput setaf 1)About to debootstrap into /mnt/zfs$(tput sgr0) --------------------"
zpool status -v
zfs list -t all
echo "------- $(tput setaf 1)Please check the above listings to be sure they're right$(tput sgr0) ------------"
echo "------- $(tput setaf 3)Press <enter> About to debootstrap into /mnt/zfs$(tput sgr0) --------------------"
read QUIT
# Install core system - need wget to get signing keys in Setup.sh
debootstrap --arch=amd64 --include=wget ${SUITE} /mnt/zfs ${DEBOOTSTRAP}
# Ugly hack to use same ssh host keys as build-host system - saves replacing known_hosts entries
# Copy build-host ssh keys to new debootstrap, to be moved into /etc/ssh after Setup.sh configuration
if [ "ZZ${COPY_SSH}" = "ZZy" ]; then
cp -av /etc/ssh /mnt/zfs
fi
# ======== Now create Setup.sh script ===============================================================
# Setup.sh : To use inside chroot - NOTE this runs when we actually chroot into /mnt/zfs
cat > /mnt/zfs/root/Setup.sh << __EOFSETUP__
#!/bin/bash
export BOXNAME=${BOXNAME}
export SYSNAME=${SYSNAME}
export LUKS=${LUKS}
export COPY_SSH=${COPY_SSH}
export PASSPHRASE=${PASSPHRASE}
export UEFI=${UEFI}
export SUITE=${SUITE}
export USERNAME=${USERNAME}
export UPASSWORD=${UPASSWORD}
export SSHPUBKEY="${SSHPUBKEY}"
export SIZE_SWAP=${SIZE_SWAP}
export SIZE_ZVOL=${SIZE_ZVOL}
export SWAPRESUME=${SWAPRESUME}
export USE_ZSWAP=${USE_ZSWAP}
export PARTITION_EFI=${PARTITION_EFI}
export PARTITION_GRUB=${PARTITION_GRUB}
export PARTITION_BOOT=${PARTITION_BOOT}
export PARTITION_SWAP=${PARTITION_SWAP}
export PARTITION_DATA=${PARTITION_DATA}
export PARTITION_RSVD=${PARTITION_RSVD}
__EOFSETUP__
for DISK in `seq 1 ${#DISKS[@]}` ; do
echo "DISKS[${DISK}]=${DISKS[${DISK}]}" >> /mnt/zfs/root/Setup.sh
done
# Note use of ' for this section to avoid replacing $variables - did not use ' above
cat >> /mnt/zfs/root/Setup.sh << '__EOFSETUP__'
# Stuff to do after a basic debootstrap
set -x
# Log everything we do
exec > >(tee -a /root/Setup.log) 2>&1
# Proxy
if [ ${PROXY} ]; then
# This is for apt-get
echo 'Acquire::http::proxy "${PROXY}";' > /etc/apt/apt.conf.d/03proxy
fi
# Basic network interfaces
cat >> /etc/network/interfaces << __EOF__
# The loopback network interface
auto lo
iface lo inet loopback
# The primary network interface
auto eth0
iface eth0 inet dhcp
__EOF__
# Nice clean sources.list, if on Amazon AWS grab local region archive address
# plymouth makes no sense for AWS, never see the console. PLYMOUTH variable
# is used for apt install below. AWS implies it's a VPS ...
mv /etc/apt/sources.list /etc/apt/sources.list.orig
EC2=`fgrep ec2 /etc/apt/sources.list.orig | fgrep ${SUITE} | head -1 | sed 's/^.*\/\///; s/ ${SUITE}.*//'`
if [ "ZZ${EC2}" = "ZZ" ]; then
# Not Amazon AWS, so need a source
EC2=archive.ubuntu.com/ubuntu
if [ ${SUITE} = trusty ]; then
PLYMOUTH="plymouth-theme-solar"
else
PLYMOUTH="plymouth-theme-ubuntu-logo plymouth-label"
fi
else
# Amazon AWS, so EC2 is already pointing at right local source
PLYMOUTH=""
VPS=true
fi
cat > /etc/apt/sources.list << EOF
deb http://${EC2} ${SUITE} main restricted universe multiverse
deb http://${EC2} ${SUITE}-updates main restricted universe multiverse
deb http://${EC2} ${SUITE}-backports main restricted universe multiverse
deb http://archive.canonical.com/ubuntu ${SUITE} partner
deb http://security.ubuntu.com/ubuntu ${SUITE}-security main restricted universe multiverse
EOF
if [ ${SUITE} = trusty ]; then
echo "deb http://extras.ubuntu.com/ubuntu ${SUITE} main" >> /etc/apt/sources.list
fi
# Set up for periodic apt updates
cat > /etc/apt/apt.conf.d/02periodic << EOFAPT1
// This enables periodic upgrades of packages - see /etc/cron.daily/apt for details
// NOTE: These default Ubuntu settings are in /etc/apt/apt.conf.d/20auto-upgrades
// APT::Periodic::Unattended-Upgrade "1";
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Enable "1";
APT::Periodic::Download-Upgradeable-Packages "1";
APT::Periodic::AutocleanInterval "7";
EOFAPT1
# Prevent apt-get from asking silly questions
export DEBIAN_FRONTEND=noninteractive
# apt-key adv fails within a debootstrap, so try wget
# apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 3E5C1192
# apt-key adv --keyserver keyserver.ubuntu.com --recv-keys CA8DA16B
# apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 437D05B5
# apt-key adv --keyserver keyserver.ubuntu.com --recv-keys C0B21F32
wget --no-proxy "http://keyserver.ubuntu.com:11371/pks/lookup?op=get&search=0x3E5C1192" -O- | apt-key add - > /dev/null 2>&1
wget --no-proxy "http://keyserver.ubuntu.com:11371/pks/lookup?op=get&search=0xCA8DA16B" -O- | apt-key add - > /dev/null 2>&1
wget --no-proxy "http://keyserver.ubuntu.com:11371/pks/lookup?op=get&search=0x437D05B5" -O- | apt-key add - > /dev/null 2>&1
# apt-fast PPA key
wget --no-proxy "http://keyserver.ubuntu.com:11371/pks/lookup?op=get&search=0xC0B21F32" -O- | apt-key add - > /dev/null 2>&1
# Ugly hack to prevent launching of services while setting up system with apt-get
mkdir -p /tmp/fakestart
ln -s /bin/true /tmp/fakestart/initctl
ln -s /bin/true /tmp/fakestart/invoke-rc.d
ln -s /bin/true /tmp/fakestart/restart
ln -s /bin/true /tmp/fakestart/start
ln -s /bin/true /tmp/fakestart/stop
ln -s /bin/true /tmp/fakestart/start-stop-daemon
ln -s /bin/true /tmp/fakestart/service
export PATH=/tmp/fakestart:$PATH
export LC_ALL="en_US.UTF-8"
export LANG="en_US.UTF-8"
export LANGUAGE="en_US"
# Set up locale - must set langlocale variable (defaults to en_US)
cat > /tmp/selections << EOFLOCALE
# tzdata
tzdata tzdata/Zones/US select Eastern
tzdata tzdata/Zones/America select New_York
tzdata tzdata/Areas select US
# localepurge will not take any action
localepurge localepurge/remove_no note
# Inform about new locales?
localepurge localepurge/dontbothernew boolean false
localepurge localepurge/showfreedspace boolean true
# Really remove all locales?
localepurge localepurge/none_selected boolean false
# Default locale for the system environment:
locales locales/default_environment_locale select en_US.UTF-8
localepurge localepurge/verbose boolean false
# Selecting locale files
localepurge localepurge/nopurge multiselect en, en_US.UTF-8
localepurge localepurge/use-dpkg-feature boolean true
locales locales/locales_to_be_generated multiselect en_US.UTF-8 UTF-8
localepurge localepurge/quickndirtycalc boolean true
localepurge localepurge/mandelete boolean true
EOFLOCALE
cat /tmp/selections | debconf-set-selections
echo "--- apt-get update"
apt-get update > /dev/null
apt-get -y install localepurge language-pack-en-base
locale-gen en_US en_US.UTF-8
if ! [ -e /etc/default/locale ]; then
cat > /etc/default/locale << EOF
LC_ALL=en_US.UTF-8
LANG=en_US.UTF-8
LANGUAGE=en_US
EOF
fi
echo "America/New_York" > /etc/timezone
cp -f /usr/share/zoneinfo/US/Eastern /etc/localtime
echo "${SYSNAME}" > /etc/hostname
echo "127.0.1.1 ${SYSNAME}.local ${SYSNAME}" >> /etc/hosts
apt-get -y install ubuntu-minimal software-properties-common
if [ ${SUITE} = trusty ]; then
apt-add-repository --yes ppa:zfs-native/stable
echo "--- apt-get update"
apt-get update > /dev/null
fi
apt-get -y --no-install-recommends install openssh-server mdadm gdisk parted linux-{headers,image}-generic lvm2 debian-keyring openssh-blacklist-extra most screen ntp vim git openssl openssl-blacklist openssh-blacklist htop build-essential whois avahi-{daemon,dnsconfd,utils} libnss-mdns mlocate bootlogd ubuntu-standard apt-transport-https bash-completion command-not-found friendly-recovery iputils-tracepath irqbalance manpages uuid-runtime apparmor whois grub-pc-bin acpi-support acpi most ${PLYMOUTH}
# For 16.04/xenial grub-efi-amd64 fails on non-uefi systems
if [ "ZZ${UEFI}" = "ZZy" ]; then
apt-get -y --no-install-recommends install grub-efi-amd64 efibootmgr
else
apt-get -y --no-install-recommends install grub-pc efibootmgr
fi
# Ugly hack to use same ssh host keys as build-host system - saves replacing known_hosts entries
# Copy build-host ssh keys to new debootstrap, to be moved into /etc/ssh after Setup.sh configuration
if [ "ZZ${COPY_SSH}" = "ZZy" ]; then
cp -av /ssh/* /etc/ssh
rm -rf /ssh
fi
# Set up mdadm - clear out any previous array definitions
cat /etc/mdadm/mdadm.conf | fgrep -v ARRAY > /tmp/ttt
mv /tmp/ttt /etc/mdadm/mdadm.conf
mdadm --detail --scan >> /etc/mdadm/mdadm.conf
# spl package (from ubuntu-zfs) provides /etc/hostid
rm -f /etc/hostid
if [ ${SUITE} = trusty ]; then
apt-get -y --no-install-recommends install ubuntu-zfs ubuntu-extras-keyring
fi
if [ ${SUITE} = xenial ]; then
apt-get -y --no-install-recommends install zfsutils-linux spl zfs-zed
modprobe zfs
fi
apt-get -y install zfs-initramfs
# Allow read-only zfs commands with no sudo password
cat /etc/sudoers.d/zfs | sed -e 's/#//' > /etc/sudoers.d/zfsALLOW
# Create swap
if [ ${SIZE_SWAP} != 0 ]; then
if [ "ZZ${LUKS}" = "ZZy" ]; then
echo "Create encrypted SWAP ${BOXNAME}_swap on top of ${BOXNAME}:swap"
mkswap -L "${BOXNAME}_swap" /dev/mapper/${BOXNAME}:swap
[ ${SWAPRESUME} = y ] && echo "RESUME=/dev/mapper/${BOXNAME}:swap" > /etc/initramfs-tools/conf.d/resume
else
mkswap -L "${BOXNAME}_swap" /dev/md/${BOXNAME}:swap
[ ${SWAPRESUME} = y ] && echo "RESUME=/dev/md/${BOXNAME}:swap" > /etc/initramfs-tools/conf.d/resume
fi
fi
if [ ${SIZE_ZVOL} != 0 ]; then
mkswap -L "${BOXNAME}_zwap" /dev/zvol/rpool/SWAP
fi
# Shutdown initramfs network before passing control to regular Ubuntu scripts
# Without this network config from initramfs is used forever plus causes extra
# few minutes of delay plus errors on bootup.
cat > /etc/initramfs-tools/scripts/init-bottom/network-down << '__EOFF__'
#!/bin/sh
PREREQ=""
prereqs() {
echo "$PREREQ"
}
case $1 in
# get pre-requisites
prereqs)
prereqs
exit 0
;;
esac
# Shutdown initramfs network before passing control to regular Ubuntu scripts
# Without this network config from initramfs is used forever plus causes extra
# few minutes of delay plus errors on bootup.
ifconfig eth0 0.0.0.0 down
__EOFF__
chmod +x /etc/initramfs-tools/scripts/init-bottom/network-down
if [ "ZZ${LUKS}" = "ZZy" ]; then
apt-get -y install cryptsetup
if [ "`cat /proc/cpuinfo | fgrep aes`" != "" ] ; then
echo "aesni-intel" >> /etc/modules
echo "aesni-intel" >> /etc/initramfs-tools/modules
fi
echo "aes-x86_64" >> /etc/modules
echo "aes-x86_64" >> /etc/initramfs-tools/modules
if [ ${SIZE_SWAP} != 0 ]; then
echo "ENV{DM_NAME}==\"${BOXNAME}:swap\", SYMLINK+=\"${BOXNAME}:swap\"" > /etc/udev/rules.d/99-local-crypt.rules
fi
echo "ENV{DM_NAME}==\"${BOXNAME}:rsvd\", SYMLINK+=\"${BOXNAME}:rsvd\"" >> /etc/udev/rules.d/99-local-crypt.rules
for DISK in `seq 1 ${#DISKS[@]}` ; do
echo "ENV{DM_NAME}==\"root_crypt${DISK}\", SYMLINK+=\"root_crypt${DISK}\"" >> /etc/udev/rules.d/99-local-crypt.rules
done
mkdir /etc/initramfs-tools/scripts/luks
cp /lib/cryptsetup/scripts/decrypt_derived /etc/initramfs-tools/scripts/luks/get.root_crypt.decrypt_derived
sed -i "
{ 2 a\
CRYPT_DEVICE=${BOXNAME}:rsvd \\
}
{ s/\$1/\${CRYPT_DEVICE}/g }
" /etc/initramfs-tools/scripts/luks/get.root_crypt.decrypt_derived
# Force inclusion of cryptsetup
echo "export CRYPTSETUP=y" > /usr/share/initramfs-tools/conf-hooks.d/forcecryptsetup
# reduce cryptroot timeout from 180s to 30s and remove dropping to shell if missing device
# Also ignore fstype check for ${BOXNAME}:rsvd - ZFS safety partition 9
# That is used as the source key for unlocking all the other luks devices
sed -i "
s/slumber=180/slumber=30/g
s/panic/break # panic/
/cryptsetup: unknown fstype, bad password or options/ {
i \
if [ \"\$crypttarget\" != \"${BOXNAME}:rsvd\" ] ; then
N ; N ; N ; a\
fi # check for ZFS
}
" /usr/share/initramfs-tools/scripts/local-top/cryptroot
# Help update-initramfs to find all encrypted disks for root - remove "return" from get_root_device()
sed -i '/echo "$device"/ { N ; s!echo "$device"\n\(.*\)return!echo "$device"\n\1# https://newspaint.wordpress.com/2015/03/22/installing-xubuntu-14-04-trusty-on-zfs-with-luks-encryption/\n\1# return! } ' /usr/share/initramfs-tools/hooks/cryptroot
# Create /etc/crypttab
echo "${BOXNAME}:rsvd UUID=$(blkid /dev/md/${BOXNAME}:rsvd -s UUID -o value) none luks,discard,noauto" >> /etc/crypttab
if [ ${SIZE_SWAP} != 0 ]; then
echo "${BOXNAME}:swap UUID=$(blkid /dev/md/${BOXNAME}:swap -s UUID -o value) none luks,discard,noauto,checkargs=${BOXNAME}:rsvd,keyscript=/lib/cryptsetup/scripts/decrypt_derived" >> /etc/crypttab
fi
for DISK in `seq 1 ${#DISKS[@]}` ; do
echo "root_crypt${DISK} UUID=$(blkid /dev/disk/by-id/${DISKS[${DISK}]}-part${PARTITION_DATA} -s UUID -o value) none luks,discard,noauto,checkargs=${BOXNAME}:rsvd,keyscript=/lib/cryptsetup/scripts/decrypt_derived" >> /etc/crypttab
done
# Create initramfs cryptroot
echo "target=${BOXNAME}:rsvd,source=UUID=$(blkid /dev/md/${BOXNAME}:rsvd -s UUID -o value),key=none,discard" > /etc/initramfs-tools/conf.d/cryptroot
if [ ${SIZE_SWAP} != 0 ]; then
echo "target=${BOXNAME}:swap,source=UUID=$(blkid /dev/md/${BOXNAME}:swap -s UUID -o value),key=none,discard,keyscript=/scripts/luks/get.root_crypt.decrypt_derived" >> /etc/initramfs-tools/conf.d/cryptroot
fi
for DISK in `seq 1 ${#DISKS[@]}` ; do
echo "target=root_crypt${DISK},source=UUID=$(blkid /dev/disk/by-id/${DISKS[${DISK}]}-part${PARTITION_DATA} -s UUID -o value),rootdev,keyscript=/scripts/luks/get.root_crypt.decrypt_derived" >> /etc/initramfs-tools/conf.d/cryptroot
done
#make sure that openssh-server is installed before dropbear
apt-get -y install dropbear
##### Force dropbear to use dhcp - can also set up real IP
cat > /etc/initramfs-tools/conf.d/dropbear_network << '__EOFF__'
export IP=dhcp
DROPBEAR=y
CRYPTSETUP=y
BUSYBOX=y
__EOFF__
##### Need the full version of busybox
cat > /etc/initramfs-tools/hooks/busybox2 << '__EOFF__'
#!/bin/sh
PREREQ=""
prereqs() {
echo "$PREREQ"
}
case $1 in
# get pre-requisites
prereqs)
prereqs
exit 0
;;
esac
# busybox
if [ "${BUSYBOX}" != "n" ] && [ -e /bin/busybox ]; then
. /usr/share/initramfs-tools/hook-functions
rm -f ${DESTDIR}/bin/busybox
copy_exec /bin/busybox /bin
copy_exec /usr/bin/xargs /bin
fi
__EOFF__
chmod +x /etc/initramfs-tools/hooks/busybox2
##### Create script to start md arrays no matter what
cat > /etc/initramfs-tools/scripts/init-premount/zzmdraidforce <<'__EOF__'
#!/bin/sh
PREREQ=""
prereqs() {
echo "$PREREQ"
}
case "$1" in
prereqs)
prereqs
exit 0
;;
esac
. /scripts/functions
sleep 10
echo "Looking for inactive arrays ..."
cat /proc/mdstat
echo ""
i=0;
for md in $(cat /proc/mdstat | grep inactive | cut -d\ -f1); do
devs="$(cat /proc/mdstat | grep ^${md} | cut -d\ -f5- | sed -e 's/\[[0-9]\]//g' -e 's/sd/\/dev\/sd/g')"
echo "${md} is inactive. Devices: ${devs}"
echo "Stopping ${md} ..."
mdadm --stop /dev/${md}
echo "Assembling ${md} ..."
mdadm --assemble /dev/${md} ${devs} || ( echo "Assembling ${md} (--force) ..."; mdadm --assemble --force /dev/${md} ${devs})
echo ""
i=$(( ${i} + 1 ))
done
echo ""
if [ $i -gt 0 ]; then
echo "${i} arrays were inactive."
echo "/proc/mdstat is now:"
cat /proc/mdstat
sleep 5
else
echo "All arrays seem to be active"
fi
echo ""
__EOF__
# Make it executable
chmod a+x /etc/initramfs-tools/scripts/init-premount/zzmdraidforce
##### Unlock script for dropbear in initramfs
cat > /etc/initramfs-tools/hooks/mount_cryptroot << '__EOFF__'
#!/bin/sh
# This script generates two scripts in the initramfs output,
# /root/mount_cryptroot.sh and /root/.profile
# https://projectgus.com/2013/05/encrypted-rootfs-over-ssh-with-debian-wheezy/
ALLOW_SHELL=1
# Set this to 1 before running update-initramfs if you want
# to allow authorized users to type Ctrl-C to drop to a
# root shell (useful for debugging, potential for abuse.)
#
# (Note that even with ALLOW_SHELL=0 it may still be possible
# to achieve a root shell.)
PREREQ="dropbear"
prereqs() {
echo "$PREREQ"
}
case "$1" in
prereqs)
prereqs
exit 0
;;
esac
. "${CONFDIR}/initramfs.conf"
. /usr/share/initramfs-tools/hook-functions
if [ -z ${DESTDIR} ]; then
exit
fi
# 16.04/xenial uses a tempdir for /root homedir, so need to find which one it is
# something like /root-2EpTFt/
ROOTDIR=`ls -1d ${DESTDIR}/root* | tail -1`
SCRIPT="${ROOTDIR}/mount_cryptroot.sh"
cat > "${SCRIPT}" << 'EOF'
#!/bin/sh
CMD=
while [ -z "$CMD" -o -z "`pidof askpass plymouth`" ]; do
# force use of busybox for ps
CMD=`busybox ps -o args | grep cryptsetup | grep -i open | grep -v grep`
sleep 0.1
done
while [ -n "`pidof askpass plymouth`" ]; do
$CMD && kill -9 `pidof askpass plymouth` && echo "Success"
done
EOF
chmod +x "${SCRIPT}"
# Run mount_cryptroot by default and close the login session afterwards
# If ALLOW_SHELL is set to 1, you can press Ctrl-C to get to an interactive prompt
cat > "${ROOTDIR}/.profile" << EOF
ctrl_c_exit() {
exit 1
}
ctrl_c_shell() {
# Ctrl-C during .profile appears to mangle terminal settings
reset
}
if [ "$ALLOW_SHELL" == "1" ]; then
echo "Unlocking rootfs... Type Ctrl-C for a shell."
trap ctrl_c_shell INT
else
echo "Unlocking rootfs..."
trap ctrl_c_exit INT
fi
${ROOTDIR#$DESTDIR}/mount_cryptroot.sh && exit 1 || echo "Run ./mount_cryptroot.sh to try unlocking again"
trap INT
EOF
__EOFF__
chmod +x /etc/initramfs-tools/hooks/mount_cryptroot
##### Second script to handle converting SSH keys.
# You might NOT want to use this as now your SSH keys are stored inside
# plaintext initramfs instead of only encypted volume.
cat > /etc/initramfs-tools/hooks/dropbear.fixup2 <<'__EOFF__'
#!/bin/sh
PREREQ="dropbear"
prereqs() {
echo "$PREREQ"
}
case "$1" in
prereqs)
prereqs
exit 0
;;
esac
. "${CONFDIR}/initramfs.conf"
. /usr/share/initramfs-tools/hook-functions
# Convert SSH keys
if [ "${DROPBEAR}" != "n" ] && [ -r "/etc/crypttab" ] ; then
/usr/lib/dropbear/dropbearconvert openssh dropbear /etc/ssh/ssh_host_dsa_key ${DESTDIR}/etc/dropbear/dropbear_dss_host_key
/usr/lib/dropbear/dropbearconvert openssh dropbear /etc/ssh/ssh_host_rsa_key ${DESTDIR}/etc/dropbear/dropbear_rsa_host_key
fi
__EOFF__
# Make it executable
chmod a+x /etc/initramfs-tools/hooks/dropbear.fixup2
# Put SSH pubkey in initramfs
echo "-----------------------------------------------------------------------------"
echo "Installing sshpubkey ${SSHPUBKEY}"
[ ! -e /etc/initramfs-tools/root/.ssh ] && mkdir -p /etc/initramfs-tools/root/.ssh
echo "${SSHPUBKEY}" >> /etc/initramfs-tools/root/.ssh/authorized_keys
echo "-----------------------------------------------------------------------------"
else # not LUKS
# This from https://bugs.launchpad.net/ubuntu/+source/zfs-initramfs/+bug/1530953
echo 'KERNEL=="sd*[0-9]", IMPORT{parent}=="ID_*", ENV{ID_FS_TYPE}=="zfs_member", SYMLINK+="$env{ID_BUS}-$env{ID_SERIAL}-part%n"' > /etc/udev/rules.d/61-zfs-vdev.rules
# https://bugs.launchpad.net/ubuntu/+source/zfs-initramfs/+bug/1530953/comments/28
# HRM - this one isn't working
# echo 'KERNEL=="sd*[0-9]", IMPORT{parent}=="ID_*", ENV{ID_PART_ENTRY_SCHEME}=="gpt", ENV{ID_PART_ENTRY_TYPE}=="6a898cc3-1dd2-11b2-99a6-080020736631", SYMLINK+="$env{ID_BUS}-$env{ID_SERIAL}-part%n"' > /etc/udev/rules.d/60-zfs-vdev.rules
fi # if LUKS
# Create fstab
echo "tmpfs /tmp tmpfs defaults,noatime,mode=1777 0 0" >> /etc/fstab
if [ ${SIZE_ZVOL} != 0 ]; then
echo "" >> /etc/fstab
echo "# ${BOXNAME}_zwap is the zfs SWAP zvol" >> /etc/fstab
echo "/dev/zvol/rpool/SWAP none swap defaults 0 0" >> /etc/fstab
fi
if [ ${SIZE_SWAP} != 0 ]; then
echo "" >> /etc/fstab
echo "# ${BOXNAME}_swap is the mdadm array of partition ${PARTITION_SWAP} on all drives" >> /etc/fstab
echo "UUID=$(blkid -t LABEL=${BOXNAME}_swap -s UUID -o value) none swap defaults 0 0" >>/etc/fstab
fi
if [ "ZZ${UEFI}" = "ZZy" ]; then
echo "" >> /etc/fstab
for DISK in `seq 1 ${#DISKS[@]}` ; do
echo "UUID=$(blkid -t LABEL=EFI_${DISK} -s UUID -o value) /boot/efi_${DISK} vfat defaults,nobootwait,nofail 0 0" >>/etc/fstab
done
fi
# Set GRUB to use zfs - enable zswap if USE_ZSWAP="zswap parameters"
sed -i "s/GRUB_CMDLINE_LINUX_DEFAULT.*/GRUB_CMDLINE_LINUX_DEFAULT=\"net.ifnames=0 rpool=rpool bootfs=rpool\/ROOT\/ubuntu boot=zfs bootdegraded=true ${USE_ZSWAP} splash\"/" /etc/default/grub
if [ "ZZ${LUKS}" = "ZZy" ]; then
# Export and import boot zpool to populate /etc/zfs/zpool.cache
zpool export boot
zpool import -f -d /dev/disk/by-id boot
fi
# Clear existing EFI NVRAM boot order, it's more than likely incorrect for our needs by now
# Also sets 10 second timeout for EFI boot menu just in case it was set to too low value earlier
if [ -e /sys/firmware/efi ]; then
efibootmgr --delete-bootorder --timeout 10 --write-signature
# Remove unwanted, existing boot entries from EFI list
for f in `seq 0 6`; do
efibootmgr --delete-bootnum --bootnum 000${f}
done
fi
# Install and update grub
update-grub
for DISK in `seq 1 ${#DISKS[@]}` ; do
sgdisk -C /dev/disk/by-id/${DISKS[${DISK}]}
sgdisk -h ${PARTITION_GRUB} /dev/disk/by-id/${DISKS[${DISK}]}
# Toggle boot flag is for MBR only
# sfdisk --force -A${PARTITION_GRUB} /dev/disk/by-id/${DISKS[${DISK}]}
if [ "ZZ${UEFI}" = "ZZy" ]; then
mkdir -p /boot/efi_${DISK}
mount /boot/efi_${DISK}
echo "Ignore errors from grub-install here if not in EFI mode"
grub-install --boot-directory=/boot --bootloader-id="EFI disk ${DISK}" --no-floppy --recheck --target=x86_64-efi --efi-directory=/boot/efi_${DISK} /dev/disk/by-id/${DISKS[${DISK}]}
mkdir -p /boot/efi_${DISK}/EFI/BOOT
cp -a "/boot/efi_${DISK}/EFI/EFI disk ${DISK}/grubx64.efi" /boot/efi_${DISK}/EFI/BOOT/bootx64.efi
[ -d /sys/firmware/efi ] && efibootmgr --create --disk /dev/disk/by-id/${DISKS[${DISK}]} --part ${PARTITION_EFI} --write-signature --loader '\EFI\BOOT\bootx64.efi' --label "EFI fallback disk ${DISK}"
umount /boot/efi_${DISK}
fi
grub-install /dev/disk/by-id/${DISKS[${DISK}]}
done
update-grub
# echo "--- apt-get update"
# apt-get update > /dev/null
# apt-get -y install zfs-initramfs
update-initramfs -c -k all
# Niceties - taken from Installerbox system - Install_BASICS.sh
# Nicer PS1 prompt
cat >> /etc/bash.bashrc << EOF
PS1="${debian_chroot:+($debian_chroot)}\[\$(tput setaf 2)\]\u@\[\$(tput bold)\]\[\$(tput setaf 5)\]\h\[\$(tput sgr0)\]\[\$(tput setaf 7)\]:\[\$(tput bold)\]\[\$(tput setaf 4)\]\w\[\$(tput setaf 7)\]\\$ \[\$(tput sgr0)\]"
# https://unix.stackexchange.com/questions/99325/automatically-save-bash-command-history-in-screen-session
PROMPT_COMMAND="history -a; history -c; history -r; \${PROMPT_COMMAND}"
HISTSIZE=5000
export LC_ALL=en_US.UTF-8
export LANG=en_US.UTF-8
export LANGUAGE=en_US.UTF-8
EOF
cat >> /etc/skel/.bashrc << EOF
PS1="${debian_chroot:+($debian_chroot)}\[\$(tput setaf 2)\]\u@\[\$(tput bold)\]\[\$(tput setaf 5)\]\h\[\$(tput sgr0)\]\[\$(tput setaf 7)\]:\[\$(tput bold)\]\[\$(tput setaf 4)\]\w\[\$(tput setaf 7)\]\\$ \[\$(tput sgr0)\]"
# https://unix.stackexchange.com/questions/99325/automatically-save-bash-command-history-in-screen-session
PROMPT_COMMAND="history -a; history -c; history -r; \${PROMPT_COMMAND}"
HISTSIZE=5000
EOF
cat >> /root/.bashrc << "EOF"
# PS1='\[\033[01;37m\]\[\033[01;41m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]$ '
PS1='\[\033[01;37m\]\[\033[01;41m\]\u@\[\033[00m\]\[$(tput bold)\]\[$(tput setaf 5)\]\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]$ '
# https://unix.stackexchange.com/questions/99325/automatically-save-bash-command-history-in-screen-session
PROMPT_COMMAND="history -a; history -c; history -r; ${PROMPT_COMMAND}"
HISTSIZE=5000
export LC_ALL=en_US.UTF-8
export LANG=en_US.UTF-8
export LANGUAGE=en_US.UTF-8
EOF
cat > /root/.bash_aliases << EOF
alias l='ls -la'
alias lt='ls -lat | head -25'
alias vhwinfo='wget --no-check-certificate https://vhwinfo.com/vhwinfo.sh -O - -o /dev/null|bash'
EOF
[ ! -e /home/${USERNAME} ] && useradd -c "Main user" -p `echo "${UPASSWORD}" | mkpasswd -m sha-512 --stdin` --home-dir /home/${USERNAME} --user-group --groups adm,sudo,dip,plugdev --create-home --skel /etc/skel --shell /bin/bash ${USERNAME}
mkdir -p /root/.ssh /home/${USERNAME}/.ssh
echo "${SSHPUBKEY}" >> /root/.ssh/authorized_keys
cp /root/.ssh/authorized_keys /home/${USERNAME}/.ssh
cp /root/.bash_aliases /home/${USERNAME}
chmod 700 /root/.ssh /home/${USERNAME}/.ssh
chown -R ${USERNAME}.${USERNAME} /home/${USERNAME}
# Ugh - want most as pager
update-alternatives --set pager /usr/bin/most
# Final update
apt-get -f install
apt-get -y --force-yes upgrade
exit
__EOFSETUP__
chmod +x /mnt/zfs/root/Setup.sh
# ======== END create Setup.sh script ===============================================================
# Here are a couple of helper scripts
# Replace-failed-drive.sh - goes into /root in new system, helps to replace a failed drive
# Reboot-testing.sh - goes into /root in local system, helps to enter/exit chroot
# for new system for debugging
# ============= Replacing drive helper script ====================================================
# Script to help in replacing a failed drive - goes in new /mnt/zfs system root dir
cat > /mnt/zfs/root/Replace-failed-drive.sh << '__EOFREPLACE__'
#!/bin/bash
# If you're using this script, then one of the drives has failed. You need to define a few
# things here : GOODDISK, NEWDISK and NEW
# These were the drives that were installed initially
__EOFREPLACE__
for DISK in `seq 1 ${#DISKS[@]}` ; do
echo "DISKS[${DISK}]=${DISKS[${DISK}]}" >> /mnt/zfs/root/Replace-failed-drive.sh
done
cat >> /mnt/zfs/root/Replace-failed-drive.sh << __EOFREPLACE1__
# Representative good disk - this is the source of a good partition table
# Used to create a new partition table on the NEWDISK defined below
export GOODDISK=ata-VBOX_HARDDISK_VB2d8b0815-33f95506<<--This-is-a-sample
# New replacement disk
export NEWDISK=ata-VBOX_HARDDISK_VBc6d3eb9a-d59c8e36<<--This-is-a-sample
# Suffix for new partitions and /boot/efi_ directory
NEW=NEW
# NOTE: These definitions above are just *REPRESENTATIVE* - you need to fill in your
# own real disk definitions from /dev/disk/by-id
## For testing, you can offline/delete a drive, /dev/sdc
##
## Should unmount the /boot/efi_X before deleting the drive
# umount /boot/efi_X
##
# readlink /sys/block/sdc
## ../devices/pci0000:00/0000:00:0d.0/ata6/host5/target5:0:0/5:0:0:0/block/sdc
## ^^^^^
## Force disconnect of drive
# echo 1 > /sys/block/sdX/device/delete
## ^^^
## Trigger rescan of a given port
# echo "- - -" > /sys/class/scsi_host/host5/scan
## ^^^^^
export BOXNAME=${BOXNAME}
export LUKS=${LUKS}
export ZERO=${ZERO}
export UEFI=${UEFI}
export SIZE_SWAP=${SIZE_SWAP}
export PASSPHRASE=${PASSPHRASE}
export PARTITION_EFI=${PARTITION_EFI}
export PARTITION_GRUB=${PARTITION_GRUB}
export PARTITION_BOOT=${PARTITION_BOOT}
export PARTITION_SWAP=${PARTITION_SWAP}
export PARTITION_DATA=${PARTITION_DATA}
export PARTITION_RSVD=${PARTITION_RSVD}
__EOFREPLACE1__
cat >> /mnt/zfs/root/Replace-failed-drive.sh << '__EOFREPLACE2__'
if [ ${NEWDISK} = "ata-VBOX_HARDDISK_VBc6d3eb9a-d59c8e36<<--This-is-a-sample" ] ; then
echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
echo "!! Must edit GOODDISK and NEWDISK variables !!"
echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
exit 1
fi
exec > >(tee -a /root/Replace-failed-drive.log) 2>&1
# Zero entire disk
if [ "ZZ${ZERO}" = "ZZy" ]; then
# urandom is limited, so use frandom module
[ ! -e /var/lib/dpkg/info/build-essential.list ] && apt-get -y install build-essential
if [ ! -e /usr/src/frandom ]; then
mkdir -p /usr/src/frandom
wget --no-proxy http://billauer.co.il/download/frandom-1.1.tar.gz -O /usr/src/frandom/frandom-1.1.tar.gz
tar --directory /usr/src/frandom -xvzf /usr/src/frandom/frandom-1.1.tar.gz
fi
cd /usr/src/frandom/frandom-1.1
rm -f *o
make
install -m 644 frandom.ko /lib/modules/`uname -r`/kernel/drivers/char/
depmod -a
modprobe frandom
dd if=/dev/frandom of=/dev/disk/by-id/${NEWDISK} bs=512 count=$(blockdev --getsz /dev/disk/by-id/${NEWDISK}) &
WAITPIDS="${WAITPIDS} "$!
fi
# Clear any old zpool info
zpool labelclear -f /dev/disk/by-id/${NEWDISK} > /dev/null 2>&1
[ -e /dev/disk/by-id/${NEWDISK}-part${PARTITION_DATA} ] && zpool labelclear -f /dev/disk/by-id/${NEWDISK}-part${PARTITION_DATA} > /dev/null 2>&1
mdadm --zero-superblock --force /dev/disk/by-id/${NEWDISK}*
[ -e /dev/disk/by-id/${NEWDISK}-part${PARTITION_BOOT} ] && mdadm --zero-superblock --force /dev/disk/by-id/${NEWDISK}-part${PARTITION_BOOT} > /dev/null 2>&1
[ -e /dev/disk/by-id/${NEWDISK}-part${PARTITION_SWAP} ] && mdadm --zero-superblock --force /dev/disk/by-id/${NEWDISK}-part${PARTITION_SWAP} > /dev/null 2>&1
[ -e /dev/disk/by-id/${NEWDISK}-part${PARTITION_RSVD} ] && mdadm --zero-superblock --force /dev/disk/by-id/${NEWDISK}-part${PARTITION_RSVD} > /dev/null 2>&1
# Clear any old LUKS or mdadm info
[ -e /dev/disk/by-id/${NEWDISK}-part${PARTITION_DATA} ] && dd if=/dev/zero of=/dev/disk/by-id/${NEWDISK}-part${PARTITION_DATA} bs=512 count=20480 > /dev/null 2>&1
[ -e /dev/disk/by-id/${NEWDISK}-part${PARTITION_SWAP} ] && dd if=/dev/zero of=/dev/disk/by-id/${NEWDISK}-part${PARTITION_SWAP} bs=512 count=20480 > /dev/null 2>&1
[ -e /dev/disk/by-id/${NEWDISK}-part${PARTITION_RSVD} ] && dd if=/dev/zero of=/dev/disk/by-id/${NEWDISK}-part${PARTITION_RSVD} bs=512 count=4096 > /dev/null 2>&1
sgdisk -Z /dev/disk/by-id/${NEWDISK}
sgdisk -R /dev/disk/by-id/${NEWDISK} /dev/disk/by-id/${GOODDISK} -G
partprobe /dev/disk/by-id/${NEWDISK}
# Only if we have UEFI
if [ "ZZ${UEFI}" = "ZZy" ]; then
sgdisk -c${PARTITION_EFI}:"EFI_${NEW}" /dev/disk/by-id/${NEWDISK}
fi
# Always have these two
sgdisk -c${PARTITION_GRUB}:"GRUB_${NEW}" /dev/disk/by-id/${NEWDISK}
sgdisk -c${PARTITION_RSVD}:"RSVD_${NEW}" /dev/disk/by-id/${NEWDISK}
# Encrypted means /boot on partition raided, and rsvd is raided
if [ "ZZ${LUKS}" = "ZZy" ]; then
sgdisk -c${PARTITION_BOOT}:"BOOT_${NEW}" /dev/disk/by-id/${NEWDISK}
fi
# Only if swap partition
if [ ${SIZE_SWAP} != 0 ]; then
sgdisk -c${PARTITION_SWAP}:"SWAP_${NEW}" /dev/disk/by-id/${NEWDISK}
fi
sgdisk -c${PARTITION_DATA}:"ZFS_${NEW}" /dev/disk/by-id/${NEWDISK}
partprobe /dev/disk/by-id/${NEWDISK}
if [ "ZZ${LUKS}" = "ZZy" ]; then
mdadm --manage /dev/md/${BOXNAME}:boot --add /dev/disk/by-id/${NEWDISK}-part${PARTITION_BOOT}
mdadm --manage /dev/md/${BOXNAME}:rsvd --add /dev/disk/by-id/${NEWDISK}-part${PARTITION_RSVD}
fi
if [ ${SIZE_SWAP} != 0 ]; then
mdadm --manage /dev/md/${BOXNAME}:swap --add /dev/disk/by-id/${NEWDISK}-part${PARTITION_SWAP}
fi
mkfs.vfat -v -F32 -s2 -n "EFI_${NEW}" /dev/disk/by-id/${NEWDISK}-part${PARTITION_EFI}
if [ "ZZ${LUKS}" = "ZZy" ]; then
# Replace failed zpool drive/partition with new encrypted partition
OLDPART="/dev/mapper/`zpool status -v | fgrep FAULTED | tr -s ' ' | cut -d' ' -f2`"
NEWPART=/dev/mapper/root_crypt${NEW}
# Create new root_crypt${NEW}, add derived key to it
echo ${PASSPHRASE} | cryptsetup --batch-mode luksFormat -c aes-xts-plain64 -s 512 -h sha512 /dev/disk/by-id/${NEWDISK}-part${PARTITION_DATA}
echo ${PASSPHRASE} | cryptsetup luksOpen /dev/disk/by-id/${NEWDISK}-part${PARTITION_DATA} root_crypt${NEW}
ln -sf /dev/mapper/root_crypt${NEW} /dev/root_crypt${NEW}
/lib/cryptsetup/scripts/decrypt_derived ${BOXNAME}:rsvd > /tmp/key
echo ${PASSPHRASE} | cryptsetup luksAddKey /dev/disk/by-id/${NEWDISK}-part${PARTITION_DATA} /tmp/key
# Recreate crypttab
# Remove old disk
cp /etc/crypttab /etc/crypttab.backup
cat /etc/crypttab.backup | fgrep -v `basename ${OLDPART}` > /etc/crypttab
# Add new disk
echo "root_crypt${NEW} UUID=$(blkid /dev/disk/by-id/${NEWDISK}-part${PARTITION_DATA} -s UUID -o value) none luks,discard,noauto,checkargs=${BOXNAME}:swap,keyscript=/lib/cryptsetup/scripts/decrypt_derived" >> /etc/crypttab
# Recreate cryptroot
# Remove old disk
cp /etc/initramfs-tools/conf.d/cryptroot /etc/initramfs-tools/conf.d/cryptroot.backup
cat /etc/initramfs-tools/conf.d/cryptroot.backup | fgrep -v `basename ${OLDPART}` > /etc/initramfs-tools/conf.d/cryptroot
# Add new disk
echo "target=root_crypt${NEW},source=UUID=$(blkid /dev/disk/by-id/${NEWDISK}-part${PARTITION_DATA} -s UUID -o value),rootdev,keyscript=/scripts/luks/get.root_crypt.decrypt_derived" >> /etc/initramfs-tools/conf.d/cryptroot
else
# Replace failed zpool drive/partition with new drive/partition
OLDPART="/`zpool status -v | fgrep was | cut -d'/' -f2-`"
# NEWPART="/dev/disk/by-id/`ls -al /dev/disk/by-id | fgrep ${NEWDISK}-part${PARTITION_DATA} | sed -e 's/.*\(ata.*\) ->.*/\1/'`"
NEWPART="/dev/disk/by-id/${NEWDISK}-part${PARTITION_DATA}"
ln -sf /dev/disk/by-id/${NEWDISK}-part${PARTITION_DATA} /dev
fi
# Recreate fstab /boot/efi entries
# Add new disk
if [ "ZZ${UEFI}" = "ZZy" ]; then
mkdir -p /boot/efi_${NEW}
echo "UUID=$(blkid -t LABEL=EFI_${NEW} -s UUID -o value) /boot/efi_${NEW} vfat defaults,nobootwait,nofail 0 0" >>/etc/fstab
mount /boot/efi_${NEW}
# Copy EFI stuff from good disk to new disk (/boot/efi_${NEW})
cp -a `cat /etc/fstab | fgrep "\`blkid /dev/disk/by-id/${GOODDISK}-part${PARTITION_EFI} -s UUID -o value\`" | cut -d' ' -f2`/* /boot/efi_${NEW}
# Remove old /boot/efi_ (not mounted because ... disk is gone) dir from fstab
OLDEFI=`( mount | fgrep /boot/efi_ | cut -d' ' -f3 ; fgrep /boot/efi_ /etc/fstab | cut -d' ' -f2 ) | sort | uniq -u`
umount -f ${OLDEFI}
rm -rf ${OLDEFI}
cp /etc/fstab /etc/fstab.backup
cat /etc/fstab.backup | fgrep -v ${OLDEFI} > /etc/fstab
fi
zpool replace rpool ${OLDPART} ${NEWPART}
zpool status -v
# Tell initramfs about new cryptroot etc
update-initramfs -c -k all
__EOFREPLACE2__
chmod +x /mnt/zfs/root/Replace-failed-drive.sh
# ============= Replacing drive helper script ====================================================
# ============= Reboot testing helper script =====================================================
# This goes in build-system to allow easy entry/exit from chroot new system in /mnt/zfs
cat > /root/Reboot-testing.sh << __EOFSETUP__
#!/bin/bash
# This script is to help with testing the newly installed zfs-on-root(-on luks maybe) system
# Invoked as Reboot-testing.sh will simply import the zpool (after possibly opening luks devices)
# bind-mount dev/sys/proc and start a new shell for you to work in. Exit that shell and it
# unmounts the bind-mounts and exports the zpool
# Invoked with -y does the same but actually chroots into the mounted system in /mnt/zfs
export BOXNAME=${BOXNAME}
export LUKS=${LUKS}
export PASSPHRASE=${PASSPHRASE}
export UEFI=${UEFI}
export USERNAME=${USERNAME}
export UPASSWORD=${UPASSWORD}
export SSHPUBKEY="${SSHPUBKEY}"
export SIZE_SWAP=${SIZE_SWAP}
export PARTITION_EFI=${PARTITION_EFI}
export PARTITION_GRUB=${PARTITION_GRUB}
export PARTITION_BOOT=${PARTITION_BOOT}
export PARTITION_SWAP=${PARTITION_SWAP}
export PARTITION_DATA=${PARTITION_DATA}
export PARTITION_RSVD=${PARTITION_RSVD}
__EOFSETUP__
for DISK in `seq 1 ${#DISKS[@]}` ; do
echo "DISKS[${DISK}]=${DISKS[${DISK}]}" >> /root/Reboot-testing.sh
done
cat >> /root/Reboot-testing.sh << '__EOFREBOOT__'
if [ "ZZ${LUKS}" = "ZZy" ]; then
if [ ${SIZE_SWAP} != 0 ]; then
echo ${PASSPHRASE} | cryptsetup luksOpen /dev/md/${BOXNAME}:swap ${BOXNAME}:swap
ln -sf /dev/mapper/${BOXNAME}:swap /dev
fi
echo ${PASSPHRASE} | cryptsetup luksOpen /dev/md/${BOXNAME}:rsvd ${BOXNAME}:rsvd
ln -sf /dev/mapper/${BOXNAME}:rsvd /dev
for DISK in `seq 1 ${#DISKS[@]}` ; do
echo ${PASSPHRASE} | cryptsetup luksOpen /dev/disk/by-id/${DISKS[${DISK}]}-part${PARTITION_DATA} root_crypt${DISK}
ln -sf /dev/mapper/root_crypt${DISK} /dev/root_crypt${DISK}
# /boot partition is NOT encrypted, so use by-id
ln -sf /dev/disk/by-id/${DISKS[${DISK}]}-part${PARTITION_BOOT} /dev
done
zpool import -f -d /dev/mapper -R /mnt/zfs rpool
else
for DISK in `seq 1 ${#DISKS[@]}` ; do
ln -sf /dev/disk/by-id/${DISKS[${DISK}]}-part${PARTITION_DATA} /dev
done
zpool import -f -d /dev/disk/by-id -R /mnt/zfs rpool
fi # LUKS
zfs mount rpool/ROOT/ubuntu
if [ "ZZ${LUKS}" = "ZZy" ]; then
rm -rf /mnt/zfs/boot/grub
zpool import -f -d /dev/disk/by-id -R /mnt/zfs boot
fi
[ ! -e /mnt/zfs/etc/mtab ] && ln -s /proc/mounts /mnt/zfs/etc/mtab
mount -o bind /proc /mnt/zfs/proc
mount -o bind /dev /mnt/zfs/dev
mount -o bind /dev/pts /mnt/zfs/dev/pts
mount -o bind /sys /mnt/zfs/sys
# Only chroot if we passed -y into script
if [ "$1" = "-y" ]; then
chroot /mnt/zfs /bin/bash --login
else
bash --login
fi
umount /mnt/zfs/boot/efi_* > /dev/null 2>&1
umount /mnt/zfs/sys
umount /mnt/zfs/dev/pts
umount /mnt/zfs/proc
umount /mnt/zfs/dev
if [ "ZZ${LUKS}" = "ZZy" ]; then
zpool export boot
fi
zpool export rpool
if [ "ZZ${LUKS}" = "ZZy" ]; then
if [ ${SIZE_SWAP} != 0 ]; then
cryptsetup luksClose ${BOXNAME}:swap
fi
cryptsetup luksClose ${BOXNAME}:rsvd
for DISK in `seq 1 ${#DISKS[@]}` ; do
cryptsetup luksClose root_crypt${DISK}
done
fi # LUKS
__EOFREBOOT__
chmod +x /root/Reboot-testing.sh
# ============= END Reboot testing helper script =====================================================
# Snapshot the clean debootstrap install
zfs snap rpool/ROOT/ubuntu@debootstrap
if [ "ZZ${LUKS}" = "ZZy" ]; then
zfs snap boot/ubuntu@debootstrap
fi
# Bind mount and chroot into new system
[ ! -e /mnt/zfs/etc/hostid ] && hostid > /mnt/zfs/etc/hostid
[ ! -e /mnt/zfs/etc/mtab ] && ln -s /proc/mounts /mnt/zfs/etc/mtab
mount -o bind /proc /mnt/zfs/proc
mount -o bind /dev /mnt/zfs/dev
mount -o bind /dev/pts /mnt/zfs/dev/pts
mount -o bind /sys /mnt/zfs/sys
# chroot into new system and run Setup.sh
chroot /mnt/zfs /bin/bash --login -c /root/Setup.sh
# After exit from chroot continue from here
umount /mnt/zfs/sys
umount /mnt/zfs/dev/pts
umount /mnt/zfs/proc
umount /mnt/zfs/dev
if [ "ZZ${LUKS}" = "ZZy" ]; then
echo "# ***************************************************************************************"
echo "#"
echo "# Do not forget to save (and encrypt) the LUKS header backup files"
echo "#"
for LUKSBACKUP in LUKS-header* ; do
echo "# ${LUKSBACKUP}"
cp ${LUKSBACKUP} /mnt/zfs/root
done
chmod 700 /mnt/zfs/root/LUKS*
echo "#"
echo "# ***************************************************************************************"
fi
if [ "ZZ${LUKS}" = "ZZy" ]; then
zpool export boot
fi
zpool export rpool
exit
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment