Compare commits
	
		
			9 Commits
		
	
	
		
			4ccce61aab
			...
			7b3f0e5f0d
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 7b3f0e5f0d | |||
| 0767984729 | |||
| 19b96b4ade | |||
| d17073dc7f | |||
| 64b36c0c67 | |||
| 337fe22b29 | |||
| 0741e5ea6b | |||
| 5642779dbf | |||
| 0f52de5b66 | 
							
								
								
									
										84
									
								
								buildiso.sh
									
									
									
									
									
								
							
							
						
						
									
										84
									
								
								buildiso.sh
									
									
									
									
									
								
							@@ -63,85 +63,87 @@ while [ $# -gt 0 ]; do
 | 
			
		||||
    esac
 | 
			
		||||
done
 | 
			
		||||
 | 
			
		||||
PACKAGE_LIST_MAIN="live-tools live-boot live-boot-initramfs-tools linux-image-amd64 mdadm lvm2 parted gdisk dosfstools debootstrap grub-pc-bin grub-efi-amd64 sipcalc vim ca-certificates vlan tftp-hpa curl ipmitool"
 | 
			
		||||
PACKAGE_LIST_NONFREE="firmware-bnx2 firmware-bnx2x"
 | 
			
		||||
 | 
			
		||||
mkdir -p artifacts/lb
 | 
			
		||||
pushd artifacts/lb &>/dev/null
 | 
			
		||||
 | 
			
		||||
echo "Pre-cleaning live-build environment..."
 | 
			
		||||
sudo lb clean
 | 
			
		||||
echo
 | 
			
		||||
 | 
			
		||||
echo "Initializing config..."
 | 
			
		||||
# Initialize the live-build config
 | 
			
		||||
lb config --distribution buster --architectures amd64 --archive-areas "main contrib non-free" --apt-recommends false
 | 
			
		||||
lb config --distribution buster --architectures amd64 --archive-areas "main contrib non-free" --apt-recommends false || fail "Failed to initialize live-build config"
 | 
			
		||||
echo
 | 
			
		||||
 | 
			
		||||
# Configure the "standard" live task (no GUI)
 | 
			
		||||
echo "live-task-standard" > config/package-lists/desktop.list.chroot
 | 
			
		||||
 | 
			
		||||
# Add additional live packages
 | 
			
		||||
echo ${PACKAGE_LIST_MAIN} > config/package-lists/installer.list.chroot
 | 
			
		||||
echo ${PACKAGE_LIST_NONFREE} > config/package-lists/nonfree.list.chroot
 | 
			
		||||
# Configure the package lists
 | 
			
		||||
echo -n "Copying package lists... "
 | 
			
		||||
cp ../../templates/installer.list.chroot config/package-lists/installer.list.chroot || fail "Failed to copy critical template file"
 | 
			
		||||
cp ../../templates/firmware.list.chroot config/package-lists/firmware.list.chroot || fail "Failed to copy critical template file"
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
# Add root password hook
 | 
			
		||||
echo -n "Copying live-boot templates... "
 | 
			
		||||
mkdir -p config/includes.chroot/lib/live/boot/
 | 
			
		||||
cp ../../templates/9990-initramfs-tools.sh config/includes.chroot/lib/live/boot/9990-initramfs-tools.sh || fail "Failed to copy critical template file"
 | 
			
		||||
chmod +x config/includes.chroot/lib/live/boot/9990-initramfs-tools.sh || fail "Failed to copy critical template file"
 | 
			
		||||
mkdir -p config/includes.chroot/lib/live/config/
 | 
			
		||||
cat <<EOF > config/includes.chroot/lib/live/config/2000-remove-root-pw
 | 
			
		||||
#!/bin/sh
 | 
			
		||||
echo "I: remove root password"
 | 
			
		||||
passwd --delete root
 | 
			
		||||
EOF
 | 
			
		||||
chmod +x config/includes.chroot/lib/live/config/2000-remove-root-pw
 | 
			
		||||
cp ../../templates/2000-remove-root-pw.sh config/includes.chroot/lib/live/config/2000-remove-root-pw.sh || fail "Failed to copy critical template file"
 | 
			
		||||
chmod +x config/includes.chroot/lib/live/config/2000-remove-root-pw.sh || fail "Failed to copy critical template file"
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
# Set root bashrc
 | 
			
		||||
echo -n "Copying root bashrc template... "
 | 
			
		||||
mkdir -p config/includes.chroot/root
 | 
			
		||||
echo "/install.sh" > config/includes.chroot/root/.bashrc
 | 
			
		||||
cp ../../templates/root.bashrc config/includes.chroot/root/.bashrc || fail "Failed to copy critical template file"
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
# Set hostname and resolv.conf
 | 
			
		||||
echo -n "Copying networking templates... "
 | 
			
		||||
mkdir -p config/includes.chroot/etc
 | 
			
		||||
echo "pvc-live-installer" > config/includes.chroot/etc/hostname
 | 
			
		||||
echo "nameserver 8.8.8.8" > config/includes.chroot/etc/resolv.conf
 | 
			
		||||
cp ../../templates/hostname config/includes.chroot/etc/hostname || fail "Failed to copy critical template file"
 | 
			
		||||
cp ../../templates/resolv.conf config/includes.chroot/etc/resolv.conf || fail "Failed to copy critical template file"
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
# Set single vty
 | 
			
		||||
# Set single vty and autologin
 | 
			
		||||
echo -n "Copying getty templates... "
 | 
			
		||||
mkdir -p config/includes.chroot/etc/systemd/
 | 
			
		||||
cat <<EOF > config/includes.chroot/etc/systemd/logind.conf
 | 
			
		||||
[Login]
 | 
			
		||||
NAutoVTs=2
 | 
			
		||||
EOF
 | 
			
		||||
 | 
			
		||||
cp ../../templates/logind.conf config/includes.chroot/etc/systemd/logind.conf || fail "Failed to copy critical template file"
 | 
			
		||||
mkdir -p config/includes.chroot/etc/systemd/system/getty@.service.d
 | 
			
		||||
cat <<EOF > config/includes.chroot/etc/systemd/system/getty@.service.d/override.conf
 | 
			
		||||
[Service]
 | 
			
		||||
ExecStart=
 | 
			
		||||
ExecStart=-/sbin/agetty -o '-p -- \\\u' --autologin root --noclear %I \$TERM
 | 
			
		||||
EOF
 | 
			
		||||
 | 
			
		||||
cp ../../templates/getty-override.conf  config/includes.chroot/etc/systemd/system/getty@.service.d/override.conf || fail "Failed to copy critical template file"
 | 
			
		||||
mkdir -p config/includes.chroot/etc/systemd/system/serial-getty@.service.d
 | 
			
		||||
cat <<EOF > config/includes.chroot/etc/systemd/system/serial-getty@.service.d/override.conf
 | 
			
		||||
[Service]
 | 
			
		||||
ExecStart=
 | 
			
		||||
ExecStart=-/sbin/agetty -o '-p -- \\\u' --autologin root --noclear --keep-baud 115200,38400,9600 %I \$TERM
 | 
			
		||||
EOF
 | 
			
		||||
cp ../../templates/serial-getty-override.conf config/includes.chroot/etc/systemd/system/serial-getty@.service.d/override.conf || fail "Failed to copy critical template file"
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
# Install GRUB config, theme, and splash
 | 
			
		||||
echo -n "Copying GRUB templates... "
 | 
			
		||||
mkdir -p config/includes.chroot/boot/grub
 | 
			
		||||
cp ../../grub.cfg config/includes.chroot/boot/grub/grub.cfg
 | 
			
		||||
cp ../../theme.txt config/includes.chroot/boot/grub/theme.txt
 | 
			
		||||
cp ../../splash.png config/includes.chroot/splash.png
 | 
			
		||||
cp ../../templates/grub.cfg config/includes.chroot/boot/grub/grub.cfg || fail "Failed to copy critical template file"
 | 
			
		||||
cp ../../templates/theme.txt config/includes.chroot/boot/grub/theme.txt || fail "Failed to copy critical template file"
 | 
			
		||||
cp ../../templates/splash.png config/includes.chroot/splash.png || fail "Failed to copy critical template file"
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
# Install install.sh script
 | 
			
		||||
cp ../../install.sh config/includes.chroot/install.sh
 | 
			
		||||
echo -n "Copying PVC node installer script template... "
 | 
			
		||||
cp ../../templates/install.sh config/includes.chroot/install.sh || fail "Failed to copy critical template file"
 | 
			
		||||
chmod +x config/includes.chroot/install.sh
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
# Customize install.sh script
 | 
			
		||||
echo -n "Customizing PVC node installer script... "
 | 
			
		||||
sed -i "s/XXDATEXX/$(date)/g" config/includes.chroot/install.sh
 | 
			
		||||
sed -i "s/XXDEPLOYUSERXX/${deployusername}/g" config/includes.chroot/install.sh
 | 
			
		||||
echo "done."
 | 
			
		||||
echo
 | 
			
		||||
 | 
			
		||||
# Build the live image
 | 
			
		||||
echo "Building live image..."
 | 
			
		||||
sudo lb build
 | 
			
		||||
sudo lb build || fail "Failed to build live image"
 | 
			
		||||
echo
 | 
			
		||||
 | 
			
		||||
# Move the ISO image out
 | 
			
		||||
echo -n "Copying generated ISO to repository root... "
 | 
			
		||||
cp live-image-amd64.hybrid.iso ../../${isofilename}
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
# Clean up the artifacts
 | 
			
		||||
if [[ -z ${preserve_artifacts} ]]; then
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										23
									
								
								buildpxe.sh
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								buildpxe.sh
									
									
									
									
									
								
							@@ -108,25 +108,6 @@ build_pxe() {
 | 
			
		||||
    rmdir ${tmpdir}
 | 
			
		||||
    echo "done."
 | 
			
		||||
 | 
			
		||||
    echo -n "Creating base iPXE configuration... "
 | 
			
		||||
    cat <<EOF > ${outputdir}/boot.pxe
 | 
			
		||||
#!ipxe
 | 
			
		||||
 | 
			
		||||
# Set global variables
 | 
			
		||||
set root-url tftp://\${next-server}
 | 
			
		||||
 | 
			
		||||
set menu-default pvc-installer
 | 
			
		||||
set submenu-default pvc-installer
 | 
			
		||||
 | 
			
		||||
:pvc-installer
 | 
			
		||||
kernel \${root-url}/vmlinuz
 | 
			
		||||
initrd \${root-url}/initrd.img
 | 
			
		||||
imgargs vmlinuz console=tty0 vga=normal nomodeset boot=live components ethdevice-timeout=600 timezone=America/Toronto fetch=\${root-url}/filesystem.squashfs username=root pvcinstall.preseed=on pvcinstall.seed_host=\${next-server} pvcinstall.seed_file=/host/mac-\${mac:hexraw}.preseed
 | 
			
		||||
 | 
			
		||||
boot
 | 
			
		||||
EOF
 | 
			
		||||
    echo "done."
 | 
			
		||||
 | 
			
		||||
    echo -n "Downloading iPXE binary undionly.kpxe (chainloads arbitrary PXE clients)... "
 | 
			
		||||
    pushd ${outputdir} &>/dev/null
 | 
			
		||||
    wget -O undionly.kpxe https://boot.ipxe.org/undionly.kpxe &>/dev/null || fail "failed to download undionly.kpxe."
 | 
			
		||||
@@ -139,6 +120,10 @@ EOF
 | 
			
		||||
    popd &>/dev/null
 | 
			
		||||
    echo "done."
 | 
			
		||||
 | 
			
		||||
    echo -n "Copying base iPXE configuration... "
 | 
			
		||||
    cp templates/boot.pxe ${outputdir}/boot.pxe
 | 
			
		||||
    echo "done."
 | 
			
		||||
 | 
			
		||||
    sudo chown -R $(whoami) ${outputdir}
 | 
			
		||||
    sudo chmod -R u+w ${outputdir}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										863
									
								
								install.sh
									
									
									
									
									
								
							
							
						
						
									
										863
									
								
								install.sh
									
									
									
									
									
								
							@@ -1,863 +0,0 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
 | 
			
		||||
logfile="/tmp/pvc-install.log"
 | 
			
		||||
lockfile="/run/pvc-install.lock"
 | 
			
		||||
 | 
			
		||||
if [[ $( whoami ) != "root" ]]; then
 | 
			
		||||
    echo "STOP! This script is designed to run as root within the installer only!"
 | 
			
		||||
    echo "Do not run it on your system. To build a PVC installer ISO, use './buildiso.sh' instead!"
 | 
			
		||||
    exit 1
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# Random delay to prevent overlaps
 | 
			
		||||
DELAY=$(( ${RANDOM} % 10 ))
 | 
			
		||||
echo -n "Waiting ${DELAY} seconds... "
 | 
			
		||||
sleep ${DELAY}
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
if [[ -f ${lockfile} ]]; then
 | 
			
		||||
    echo "An instance of 'install.sh' is already running!"
 | 
			
		||||
    exit 1
 | 
			
		||||
fi
 | 
			
		||||
touch ${lockfile}
 | 
			
		||||
 | 
			
		||||
iso_name="XXDATEXX"
 | 
			
		||||
target_deploy_user="XXDEPLOYUSERXX"
 | 
			
		||||
 | 
			
		||||
supported_debrelease="buster bullseye"
 | 
			
		||||
default_debrelease="buster"
 | 
			
		||||
default_debmirror="http://debian.mirror.rafal.ca/debian"
 | 
			
		||||
 | 
			
		||||
inclpkglist="lvm2,parted,gdisk,grub-pc,grub-efi-amd64,linux-image-amd64,sudo,vim,gpg,gpg-agent,aptitude,openssh-server,vlan,ifenslave,python3,ca-certificates,curl"
 | 
			
		||||
suppkglist="firmware-linux,firmware-linux-nonfree,firmware-bnx2,firmware-bnx2x,ntp"
 | 
			
		||||
 | 
			
		||||
# DANGER - THIS PASSWORD IS PUBLIC
 | 
			
		||||
# It should be used ONLY immediately after booting the PVC node in a SECURE environment
 | 
			
		||||
# to facilitate troubleshooting of a failed boot. It should NOT be exposed to the Internet,
 | 
			
		||||
# and it should NOT be left in place after system configuration. The PVC Ansible deployment
 | 
			
		||||
# roles will overwrite it by default during configuration.
 | 
			
		||||
root_password="hCb1y2PF"
 | 
			
		||||
 | 
			
		||||
# Respawn function
 | 
			
		||||
respawn() (
 | 
			
		||||
    $0 & disown
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
# Checkin function
 | 
			
		||||
seed_checkin() (
 | 
			
		||||
    case ${1} in
 | 
			
		||||
        start)
 | 
			
		||||
            action="install-start"
 | 
			
		||||
        ;;
 | 
			
		||||
        end)
 | 
			
		||||
            action="install-complete"
 | 
			
		||||
        ;;
 | 
			
		||||
    esac
 | 
			
		||||
    macaddr=$( ip -br link show ${target_interface} | awk '{ print $3 }' )
 | 
			
		||||
    ipaddr=$( ip -br address show ${target_interface} | awk '{ print $3 }' | awk -F '/' '{ print $1 }' )
 | 
			
		||||
    curl -X POST \
 | 
			
		||||
        -H "Content-Type: application/json" \
 | 
			
		||||
        -d "{\"action\":\"${action}\",\"macaddr\":\"${macaddr}\",\"ipaddr\":\"${ipaddr}\",\"hostname\":\"${target_hostname}\",\"bmc_macaddr\":\"${bmc_macaddr}\",\"bmc_ipaddr\":\"${bmc_ipaddr}\"}" \
 | 
			
		||||
        ${pvcbootstrapd_checkin_uri}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
# Obtain the preseed options from the kernel command line
 | 
			
		||||
install_option=""
 | 
			
		||||
seed_host=""
 | 
			
		||||
seed_file=""
 | 
			
		||||
kernel_cmdline=( $( cat /proc/cmdline ) )
 | 
			
		||||
for option in ${kernel_cmdline[@]}; do
 | 
			
		||||
    case ${option} in
 | 
			
		||||
        pvcinstall.preseed=*)
 | 
			
		||||
            install_option=${option#pvcinstall.preseed=}
 | 
			
		||||
        ;;
 | 
			
		||||
        pvcinstall.seed_host=*)
 | 
			
		||||
            seed_host=${option#pvcinstall.seed_host=}
 | 
			
		||||
        ;;
 | 
			
		||||
        pvcinstall.seed_file=*)
 | 
			
		||||
            seed_file=${option#pvcinstall.seed_file=}
 | 
			
		||||
        ;;
 | 
			
		||||
    esac
 | 
			
		||||
done
 | 
			
		||||
 | 
			
		||||
seed_config() {
 | 
			
		||||
    # Get IPMI BMC MAC for checkings
 | 
			
		||||
    bmc_macaddr="$( ipmitool lan print | grep 'MAC Address  ' | awk '{ print $NF }' )"
 | 
			
		||||
    bmc_ipaddr="$( ipmitool lan print | grep 'IP Address  ' | awk '{ print $NF }' )"
 | 
			
		||||
 | 
			
		||||
    # Perform DHCP on all interfaces to come online
 | 
			
		||||
    for interface in $( ip address | grep '^[0-9]' | grep 'eno\|enp\|ens\|wlp' | awk '{ print $2 }' | tr -d ':' ); do
 | 
			
		||||
        ip link set ${interface} up
 | 
			
		||||
        pgrep dhclient || dhclient ${interface}
 | 
			
		||||
    done
 | 
			
		||||
 | 
			
		||||
    # Fetch the seed config
 | 
			
		||||
    tftp -m binary "${seed_host}" -c get "${seed_file}" /tmp/install.seed
 | 
			
		||||
 | 
			
		||||
    . /tmp/install.seed || exit 1
 | 
			
		||||
 | 
			
		||||
    # Handle the target interface
 | 
			
		||||
    target_route="$( ip route show to match ${seed_host} | grep 'scope link' )"
 | 
			
		||||
    target_interface="$( grep -E -o 'e[a-z]+[0-9]+[a-z0-9]*' <<<"${target_route}" )"
 | 
			
		||||
 | 
			
		||||
    # Handle the target disk
 | 
			
		||||
    if [[ -n ${target_disk_path} ]]; then
 | 
			
		||||
        target_disk="$( realpath ${target_disk_path} )"
 | 
			
		||||
    else
 | 
			
		||||
        # Find the (first) disk with the given model
 | 
			
		||||
        for disk in /dev/sd?; do
 | 
			
		||||
            disk_model="$( fdisk -l ${disk} | grep 'Disk model:' | sed 's/Disk model: //g' )"
 | 
			
		||||
            if [[ ${disk_model} == ${target_disk_model} ]]; then
 | 
			
		||||
                target_disk="${disk}"
 | 
			
		||||
                break
 | 
			
		||||
            fi
 | 
			
		||||
        done
 | 
			
		||||
    fi
 | 
			
		||||
    if [[ ! -b ${target_disk} ]]; then
 | 
			
		||||
        echo "Invalid disk or disk not found!"
 | 
			
		||||
        exit 1
 | 
			
		||||
    fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interactive_config() {
 | 
			
		||||
    clear
 | 
			
		||||
 | 
			
		||||
    echo "--------------------------------------------------------"
 | 
			
		||||
    echo "| PVC Node installer (${iso_name}) |"
 | 
			
		||||
    echo "--------------------------------------------------------"
 | 
			
		||||
    echo
 | 
			
		||||
    echo "This LiveCD will install a PVC node base system ready for bootstrapping with 'pvc-ansible'."
 | 
			
		||||
    echo
 | 
			
		||||
    echo "* NOTE: If you make a mistake and need to restart the installer while answering"
 | 
			
		||||
    echo "        the questions below, you may do so by typing ^C to cancel the script,"
 | 
			
		||||
    echo "        then re-running it by calling /install.sh in the resulting shell."
 | 
			
		||||
    echo
 | 
			
		||||
 | 
			
		||||
    echo "1) Please enter a fully-qualified hostname for the system. This should match the hostname"
 | 
			
		||||
    echo "in the 'pvc-ansible' inventory."
 | 
			
		||||
    while [[ -z ${target_hostname} ]]; do
 | 
			
		||||
        echo
 | 
			
		||||
        echo -n "> "
 | 
			
		||||
        read target_hostname
 | 
			
		||||
        if [[ -z ${target_hostname} ]]; then
 | 
			
		||||
            echo
 | 
			
		||||
            echo "Please enter a hostname."
 | 
			
		||||
            continue
 | 
			
		||||
        fi
 | 
			
		||||
        echo
 | 
			
		||||
    done
 | 
			
		||||
 | 
			
		||||
    disks="$(
 | 
			
		||||
        for disk in /dev/sd? /dev/nvme?n?; do
 | 
			
		||||
            if [[ ! -b ${disk} ]]; then
 | 
			
		||||
                continue
 | 
			
		||||
            fi
 | 
			
		||||
            disk_data="$( fdisk -l ${disk} 2>/dev/null )"
 | 
			
		||||
            echo -n "${disk}"
 | 
			
		||||
            echo -en "\t$( grep "^Disk model:" <<<"${disk_data}" | awk '{ $1=""; print $0 }' )"
 | 
			
		||||
            echo -en "  $( grep "^Disk ${disk}:" <<<"${disk_data}" | awk '{ $1=""; $2="size:"; print $0 }' )"
 | 
			
		||||
            echo
 | 
			
		||||
        done
 | 
			
		||||
    )"
 | 
			
		||||
 | 
			
		||||
    echo "2) Please enter the disk to install the PVC base system to. This disk will be"
 | 
			
		||||
    echo "wiped, an LVM PV created on it, and the system installed to this LVM."
 | 
			
		||||
    echo "* NOTE: PVC requires a disk of at least 30GB to be installed to, and 100GB is the"
 | 
			
		||||
    echo "recommended minimum size for optimal production partition sizes."
 | 
			
		||||
    echo "* NOTE: For optimal performance, this disk should be high-performance flash (SSD, etc.)."
 | 
			
		||||
    echo "* NOTE: This disk should be a RAID-1 volume configured in hardware, or a durable storage"
 | 
			
		||||
    echo "device, maximum redundancy and resiliency."
 | 
			
		||||
    echo
 | 
			
		||||
    echo "Available disks:"
 | 
			
		||||
    echo
 | 
			
		||||
    echo -e "$( sed 's/\(.*\)/  \1/' <<<"${disks[@]}" )"
 | 
			
		||||
    while [[ ! -b ${target_disk} ]]; do
 | 
			
		||||
        echo
 | 
			
		||||
        echo -n "> "
 | 
			
		||||
        read target_disk
 | 
			
		||||
        if [[ ! -b ${target_disk} ]]; then
 | 
			
		||||
            echo
 | 
			
		||||
            echo "Please enter a valid target disk."
 | 
			
		||||
            continue
 | 
			
		||||
        fi
 | 
			
		||||
        blockdev_size_gbytes="$(( $( blockdev --getsize64 ${target_disk} ) / 1024 / 1024 / 1024 - 1))"
 | 
			
		||||
        if [[ ${blockdev_size_gbytes} -lt 30 ]]; then
 | 
			
		||||
            target_disk=""
 | 
			
		||||
            echo
 | 
			
		||||
            echo "The specified disk is too small (<30 GB) to use as a PVC system disk."
 | 
			
		||||
            echo "Please choose an alternative disk."
 | 
			
		||||
            continue
 | 
			
		||||
        fi
 | 
			
		||||
        echo
 | 
			
		||||
    done
 | 
			
		||||
 | 
			
		||||
    for interface in $( ip address | grep '^[0-9]' | grep 'eno\|enp\|ens\|wlp' | awk '{ print $2 }' | tr -d ':' ); do
 | 
			
		||||
        ip link set ${interface} up
 | 
			
		||||
    done
 | 
			
		||||
    sleep 2
 | 
			
		||||
    interfaces="$(
 | 
			
		||||
        ip address | grep '^[0-9]' | grep 'eno\|enp\|ens\|wlp' | awk '{ print $2"\t"$3 }' | tr -d ':'
 | 
			
		||||
    )"
 | 
			
		||||
    echo "3a) Please enter the primary network interface for external connectivity. If"
 | 
			
		||||
    echo "no entries are shown here, ensure a cable is connected, then restart the"
 | 
			
		||||
    echo "installer with ^C and '/install.sh'."
 | 
			
		||||
    echo
 | 
			
		||||
    echo "Available interfaces:"
 | 
			
		||||
    echo
 | 
			
		||||
    echo -e "$( sed 's/\(.*\)/  \1/' <<<"${interfaces[@]}" )"
 | 
			
		||||
    while [[ -z ${target_interface} ]]; do
 | 
			
		||||
        echo
 | 
			
		||||
        echo -n "> "
 | 
			
		||||
        read target_interface
 | 
			
		||||
        if [[ -z ${target_interface} ]]; then
 | 
			
		||||
            echo
 | 
			
		||||
            echo "Please enter a valid interface."
 | 
			
		||||
            continue
 | 
			
		||||
        fi
 | 
			
		||||
        if ! grep -qw "${target_interface}" <<<"${interfaces[@]}"; then
 | 
			
		||||
            target_interface=""
 | 
			
		||||
            echo
 | 
			
		||||
            echo "Please enter a valid interface."
 | 
			
		||||
            continue
 | 
			
		||||
        fi
 | 
			
		||||
        echo
 | 
			
		||||
    done
 | 
			
		||||
 | 
			
		||||
    echo -n "3b) Is a tagged vLAN required for the primary network interface? [y/N] "
 | 
			
		||||
    read vlans_req
 | 
			
		||||
    if [[ ${vlans_req} == 'y' || ${vlans_req} == 'Y' ]]; then
 | 
			
		||||
        echo
 | 
			
		||||
        echo "Please enter the vLAN ID for the interface."
 | 
			
		||||
        while [[ -z ${vlan_id} ]]; do
 | 
			
		||||
            echo
 | 
			
		||||
            echo -n "> "
 | 
			
		||||
            read vlan_id
 | 
			
		||||
            if [[ -z ${vlan_id} ]]; then
 | 
			
		||||
                echo
 | 
			
		||||
                echo "Please enter a numeric vLAN ID."
 | 
			
		||||
                continue
 | 
			
		||||
            fi
 | 
			
		||||
        done
 | 
			
		||||
        echo
 | 
			
		||||
    else
 | 
			
		||||
        vlan_id=""
 | 
			
		||||
        echo
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    echo "3c) Please enter the IP address, in CIDR format [X.X.X.X/YY], of the primary"
 | 
			
		||||
    echo "network interface. Leave blank for DHCP configuration of the interface on boot."
 | 
			
		||||
    echo
 | 
			
		||||
    echo -n "> "
 | 
			
		||||
    read target_ipaddr
 | 
			
		||||
    if [[ -n ${target_ipaddr} ]]; then
 | 
			
		||||
        target_netformat="static"
 | 
			
		||||
        echo
 | 
			
		||||
        echo "3d) Please enter the default gateway IP address of the primary"
 | 
			
		||||
        echo "network interface."
 | 
			
		||||
        while [[ -z ${target_defgw} ]]; do
 | 
			
		||||
            echo
 | 
			
		||||
            echo -n "> "
 | 
			
		||||
            read target_defgw
 | 
			
		||||
            if [[ -z ${target_defgw} ]]; then
 | 
			
		||||
                echo
 | 
			
		||||
                echo "Please enter a default gateway; the installer requires Internet access."
 | 
			
		||||
                continue
 | 
			
		||||
            fi
 | 
			
		||||
            echo
 | 
			
		||||
        done
 | 
			
		||||
    else
 | 
			
		||||
        target_netformat="dhcp"
 | 
			
		||||
        echo
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    echo -n "Bringing up primary network interface in ${target_netformat} mode... "
 | 
			
		||||
    case ${target_netformat} in
 | 
			
		||||
        'static')
 | 
			
		||||
            if [[ -n ${vlan_id} ]]; then
 | 
			
		||||
                modprobe 8021q >&2
 | 
			
		||||
                vconfig add ${target_interface} ${vlan_id} >&2
 | 
			
		||||
                vlan_interface=${target_interface}.${vlan_id}
 | 
			
		||||
                ip link set ${target_interface} up >&2 || true
 | 
			
		||||
                ip link set ${vlan_interface} up >&2 || true
 | 
			
		||||
                ip address add ${target_ipaddr} dev ${vlan_interface} >&2 || true
 | 
			
		||||
                ip route add default via ${target_defgw} >&2 || true
 | 
			
		||||
                formatted_ipaddr="$( sipcalc ${target_ipaddr} | grep -v '(' | awk '/Host address/{ print $NF }' )"
 | 
			
		||||
                formatted_netmask="$( sipcalc ${target_ipaddr} | grep -v '(' | awk '/Network mask/{ print $NF }' )"
 | 
			
		||||
                real_interface="${vlan_interface}"
 | 
			
		||||
                target_interfaces_is="static-vlan"
 | 
			
		||||
            else
 | 
			
		||||
                ip link set ${target_interface} up >&2 || true
 | 
			
		||||
                ip address add ${target_ipaddr} dev ${target_interface} >&2 || true
 | 
			
		||||
                ip route add default via ${target_defgw} >&2 || true
 | 
			
		||||
                formatted_ipaddr="$( sipcalc ${target_ipaddr} | grep -v '(' | awk '/Host address/{ print $NF }' )"
 | 
			
		||||
                formatted_netmask="$( sipcalc ${target_ipaddr} | grep -v '(' | awk '/Network mask/{ print $NF }' )"
 | 
			
		||||
                real_interface="${target_interface}"
 | 
			
		||||
                target_interfaces_is="static-raw"
 | 
			
		||||
            fi
 | 
			
		||||
            cat <<EOF >/etc/resolv.conf
 | 
			
		||||
nameserver 8.8.8.8
 | 
			
		||||
EOF
 | 
			
		||||
        ;;
 | 
			
		||||
        'dhcp')
 | 
			
		||||
            if [[ -n ${vlan_id} ]]; then
 | 
			
		||||
                modprobe 8021q >&2
 | 
			
		||||
                vconfig add ${target_interface} ${vlan_id} &>/dev/null
 | 
			
		||||
                vlan_interface=${target_interface}.${vlan_id}
 | 
			
		||||
                dhclient ${vlan_interface} >&2
 | 
			
		||||
                real_interface="${vlan_interface}"
 | 
			
		||||
                target_interfaces_is="dhcp-vlan"
 | 
			
		||||
            else
 | 
			
		||||
                dhclient ${target_interface} >&2
 | 
			
		||||
                real_interface="${target_interface}"
 | 
			
		||||
                target_interfaces_is="dhcp-raw"
 | 
			
		||||
            fi
 | 
			
		||||
        ;;
 | 
			
		||||
    esac
 | 
			
		||||
    echo "done."
 | 
			
		||||
    echo
 | 
			
		||||
 | 
			
		||||
    echo -n "Waiting for networking to become ready... "
 | 
			
		||||
    while ! ping -q -c 1 8.8.8.8 &>/dev/null; do
 | 
			
		||||
        sleep 1
 | 
			
		||||
    done
 | 
			
		||||
    echo "done."
 | 
			
		||||
    echo
 | 
			
		||||
 | 
			
		||||
    echo "4a) Please enter an alternate Debian release codename for the system if desired."
 | 
			
		||||
    echo "    Supported: ${supported_debrelease}"
 | 
			
		||||
    echo "    Default: ${default_debrelease}"
 | 
			
		||||
    while [[ -z ${debrelease} ]]; do
 | 
			
		||||
        echo
 | 
			
		||||
        echo -n "> "
 | 
			
		||||
        read debrelease
 | 
			
		||||
        if [[ -z ${debrelease} ]]; then
 | 
			
		||||
            debrelease="${default_debrelease}"
 | 
			
		||||
        fi
 | 
			
		||||
        if ! grep -qw "${debrelease}" <<<"${supported_debrelease}"; then
 | 
			
		||||
            debrelease=""
 | 
			
		||||
            echo
 | 
			
		||||
            echo "Please enter a valid release."
 | 
			
		||||
            continue
 | 
			
		||||
        fi
 | 
			
		||||
        echo
 | 
			
		||||
    done
 | 
			
		||||
 | 
			
		||||
    echo "4b) Please enter an HTTP URL for an alternate Debian mirror if desired."
 | 
			
		||||
    echo "    Default: ${default_debmirror}"
 | 
			
		||||
    while [[ -z ${debmirror} ]]; do
 | 
			
		||||
        echo
 | 
			
		||||
        echo -n "> "
 | 
			
		||||
        read debmirror
 | 
			
		||||
        if [[ -z ${debmirror} ]]; then
 | 
			
		||||
            debmirror="${default_debmirror}"
 | 
			
		||||
        fi
 | 
			
		||||
        if ! wget -O /dev/null ${debmirror}/dists/${debrelease}/Release &>/dev/null; then
 | 
			
		||||
            debmirror=""
 | 
			
		||||
            echo
 | 
			
		||||
            echo "Please enter a valid Debian mirror URL."
 | 
			
		||||
            continue
 | 
			
		||||
        fi
 | 
			
		||||
        echo
 | 
			
		||||
        echo "Repository mirror '${debmirror}' successfully validated."
 | 
			
		||||
        echo
 | 
			
		||||
    done
 | 
			
		||||
 | 
			
		||||
    target_keys_method="wget"
 | 
			
		||||
    echo "5) Please enter an HTTP URL containing a text list of SSH authorized keys to"
 | 
			
		||||
    echo "fetch. These keys will be allowed access to the deployment user 'XXDEPLOYUSER'"
 | 
			
		||||
    echo "via SSH."
 | 
			
		||||
    echo ""
 | 
			
		||||
    echo "Leave blank to bypass this and use a password instead."
 | 
			
		||||
    echo
 | 
			
		||||
    echo -n "> "
 | 
			
		||||
    read target_keys_path
 | 
			
		||||
    if [[ -z ${target_keys_path} ]]; then
 | 
			
		||||
        echo
 | 
			
		||||
        echo "No SSH keys URL specified. Falling back to password configuration."
 | 
			
		||||
        echo
 | 
			
		||||
        echo "5) Please enter a password (hidden), twice, for the deployment user '${target_deploy_user}'."
 | 
			
		||||
        while [[ -z "${target_password}" ]]; do
 | 
			
		||||
            echo
 | 
			
		||||
            echo -n "> "
 | 
			
		||||
            read -s target_password_1
 | 
			
		||||
            echo
 | 
			
		||||
            echo -n "> "
 | 
			
		||||
            read -s target_password_2
 | 
			
		||||
            echo
 | 
			
		||||
            if [[ -n "${target_password_1}" && "${target_password_1}" -eq "${target_password_2}" ]]; then
 | 
			
		||||
                target_password="${target_password_1}"
 | 
			
		||||
            else
 | 
			
		||||
                echo
 | 
			
		||||
                echo "The specified passwords do not match or are empty."
 | 
			
		||||
            fi
 | 
			
		||||
        done
 | 
			
		||||
    else
 | 
			
		||||
        while ! wget -O /dev/null ${target_keys_path} &>/dev/null; do
 | 
			
		||||
            echo
 | 
			
		||||
            echo "Please enter a valid SSH keys URL."
 | 
			
		||||
            echo
 | 
			
		||||
            echo -n "> "
 | 
			
		||||
            read target_keys_path
 | 
			
		||||
        done
 | 
			
		||||
        echo
 | 
			
		||||
        echo "SSH key source '${target_keys_path}' successfully validated."
 | 
			
		||||
    fi
 | 
			
		||||
    echo
 | 
			
		||||
}    
 | 
			
		||||
 | 
			
		||||
case ${install_option} in
 | 
			
		||||
    on)
 | 
			
		||||
        seed_config
 | 
			
		||||
    ;;
 | 
			
		||||
    *)
 | 
			
		||||
        interactive_config
 | 
			
		||||
    ;;
 | 
			
		||||
esac
 | 
			
		||||
 | 
			
		||||
titlestring_text="| Proceeding with installation of host '${target_hostname}'. |"
 | 
			
		||||
titlestring_len="$(( $( wc -c <<<"${titlestring_text}" ) - 2 ))"
 | 
			
		||||
for i in $( seq 0 ${titlestring_len} ); do echo -n "-"; done; echo
 | 
			
		||||
echo "${titlestring_text}"
 | 
			
		||||
for i in $( seq 0 ${titlestring_len} ); do echo -n "-"; done; echo
 | 
			
		||||
echo
 | 
			
		||||
 | 
			
		||||
### Script begins ###
 | 
			
		||||
echo "LOGFILE: ${logfile}"
 | 
			
		||||
echo
 | 
			
		||||
 | 
			
		||||
exec 1> >( tee -ia ${logfile} )
 | 
			
		||||
exec 2> >( tee -ia ${logfile} >/dev/null )
 | 
			
		||||
set -o errexit
 | 
			
		||||
set -o xtrace
 | 
			
		||||
 | 
			
		||||
case ${install_option} in
 | 
			
		||||
    on)
 | 
			
		||||
        seed_checkin start
 | 
			
		||||
    ;;
 | 
			
		||||
    *)
 | 
			
		||||
        # noop
 | 
			
		||||
        true
 | 
			
		||||
    ;;
 | 
			
		||||
esac
 | 
			
		||||
 | 
			
		||||
cleanup() {
 | 
			
		||||
    set +o errexit
 | 
			
		||||
    echo -n "Cleaning up... "
 | 
			
		||||
    umount ${target}/tmp >&2
 | 
			
		||||
    umount ${target}/run >&2
 | 
			
		||||
    umount ${target}/sys >&2
 | 
			
		||||
    umount ${target}/proc >&2
 | 
			
		||||
    umount ${target}/dev/pts >&2
 | 
			
		||||
    umount ${target}/dev >&2
 | 
			
		||||
    umount ${target}/var/lib/ceph >&2
 | 
			
		||||
    umount ${target}/var/lib/zookeeper >&2
 | 
			
		||||
    umount ${target}/boot/efi >&2
 | 
			
		||||
    umount ${target}/boot >&2
 | 
			
		||||
    umount ${target} >&2
 | 
			
		||||
    vgchange -an >&2
 | 
			
		||||
    rmdir ${target} >&2
 | 
			
		||||
    rm ${lockfile}
 | 
			
		||||
    echo "done."
 | 
			
		||||
    echo
 | 
			
		||||
 | 
			
		||||
    case ${install_option} in
 | 
			
		||||
        on)
 | 
			
		||||
            respawn
 | 
			
		||||
        ;;
 | 
			
		||||
        *)
 | 
			
		||||
            # noop
 | 
			
		||||
            true
 | 
			
		||||
        ;;
 | 
			
		||||
    esac
 | 
			
		||||
}
 | 
			
		||||
trap cleanup EXIT
 | 
			
		||||
 | 
			
		||||
echo -n "Determining partition sizes... "
 | 
			
		||||
blockdev_size_bytes="$( blockdev --getsize64 ${target_disk} )"
 | 
			
		||||
blockdev_size_gbytes="$(( ${blockdev_size_bytes} / 1024 / 1024 / 1024 - 1))"
 | 
			
		||||
if [[ ${blockdev_size_gbytes} -ge 100 ]]; then
 | 
			
		||||
    # Optimal sized system disk (>=100GB), use large partitions
 | 
			
		||||
    size_root_lv="32"
 | 
			
		||||
    size_ceph_lv="8"
 | 
			
		||||
    size_zookeeper_lv="32"
 | 
			
		||||
    size_swap_lv="16"
 | 
			
		||||
    echo "found large disk (${blockdev_size_gbytes} >= 100GB), using optimal partition sizes."
 | 
			
		||||
else
 | 
			
		||||
    # Minimum sized disk (>=30GB), use small partitions
 | 
			
		||||
    size_root_lv="8"
 | 
			
		||||
    size_ceph_lv="4"
 | 
			
		||||
    size_zookeeper_lv="8"
 | 
			
		||||
    size_swap_lv="8"
 | 
			
		||||
    echo "found small disk (${blockdev_size_gbytes} < 100GB), using small partition sizes."
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
echo -n "Disabing existing volume groups... "
 | 
			
		||||
vgchange -an >&2 || true
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
blockcheck() {
 | 
			
		||||
    # Use for testing only
 | 
			
		||||
    if [[ -n ${SKIP_BLOCKCHECK} ]]; then
 | 
			
		||||
        return
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    # Determine optimal block size for zeroing
 | 
			
		||||
    exponent=16
 | 
			
		||||
    remainder=1
 | 
			
		||||
    while [[ ${remainder} -gt 0 && ${exponent} -gt 0 ]]; do
 | 
			
		||||
        exponent=$(( ${exponent} - 1 ))
 | 
			
		||||
        size=$(( 2**9 * 2 ** ${exponent} ))
 | 
			
		||||
        count=$(( ${blockdev_size_bytes} / ${size} ))
 | 
			
		||||
        remainder=$(( ${blockdev_size_bytes} - ${count} * ${size} ))
 | 
			
		||||
    done
 | 
			
		||||
    if [[ ${remainder} -gt 0 ]]; then
 | 
			
		||||
        echo "Failed to find a suitable block size for wiping... skipping."
 | 
			
		||||
        return
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    echo -n "Checking if block device '${target_disk}' is already wiped... "
 | 
			
		||||
    if ! cmp --silent --bytes ${blockdev_size_bytes} /dev/zero ${target_disk}; then
 | 
			
		||||
        echo "false."
 | 
			
		||||
        echo "Wiping block device '${target_disk}' (${count} blocks of ${size} bytes)..."
 | 
			
		||||
        dd if=/dev/zero of=${target_disk} bs=${size} count=${count} oflag=direct status=progress 2>&1
 | 
			
		||||
    else
 | 
			
		||||
        echo "done."
 | 
			
		||||
    fi
 | 
			
		||||
}
 | 
			
		||||
blockcheck
 | 
			
		||||
 | 
			
		||||
echo -n "Preparing block device '${target_disk}'... "
 | 
			
		||||
# New GPT, part 1 64MB ESP, part 2 960MB BOOT, part 3 inf LVM PV
 | 
			
		||||
echo -e "o\ny\nn\n1\n\n64M\nEF00\nn\n2\n\n960M\n8300\nn\n3\n\n\n8E00\nw\ny\n" | gdisk ${target_disk} >&2
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
echo -n "Rescanning disks... "
 | 
			
		||||
partprobe >&2 || true
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
echo -n "Creating LVM PV... "
 | 
			
		||||
yes | pvcreate -ffy ${target_disk}3 >&2
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
echo -n "Creating LVM VG 'vgx'... "
 | 
			
		||||
yes | vgcreate vgx ${target_disk}3 >&2
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
echo -n "Creating root logical volume (${size_root_lv}GB)... "
 | 
			
		||||
yes | lvcreate -L ${size_root_lv}G -n root vgx >&2
 | 
			
		||||
echo "done."
 | 
			
		||||
echo -n "Creating filesystem on root logical volume (ext4)... "
 | 
			
		||||
yes | mkfs.ext4 /dev/vgx/root >&2
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
echo -n "Creating ceph logical volume (${size_ceph_lv}GB)... "
 | 
			
		||||
yes | lvcreate -L ${size_ceph_lv}G -n ceph vgx >&2
 | 
			
		||||
echo "done."
 | 
			
		||||
echo -n "Creating filesystem on ceph logical volume (ext4)... "
 | 
			
		||||
yes | mkfs.ext4 /dev/vgx/ceph >&2
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
echo -n "Creating zookeeper logical volume (${size_zookeeper_lv}GB)... "
 | 
			
		||||
yes | lvcreate -L ${size_zookeeper_lv}G -n zookeeper vgx >&2
 | 
			
		||||
echo "done."
 | 
			
		||||
echo -n "Creating filesystem on zookeeper logical volume (ext4)... "
 | 
			
		||||
yes | mkfs.ext4 /dev/vgx/zookeeper >&2
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
echo -n "Creating swap logical volume (${size_swap_lv}GB)... "
 | 
			
		||||
yes | lvcreate -L ${size_swap_lv}G -n swap vgx >&2
 | 
			
		||||
echo "done."
 | 
			
		||||
echo -n "Creating swap space on swap logical volume... "
 | 
			
		||||
yes | mkswap -f /dev/vgx/swap >&2
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
echo -n "Creating filesystem on boot partition (ext2)... "
 | 
			
		||||
yes | mkfs.ext2 ${target_disk}2 >&2
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
echo -n "Creating filesystem on ESP partition (vfat)... "
 | 
			
		||||
yes | mkdosfs -F32 ${target_disk}1 >&2
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
vgchange -ay >&2
 | 
			
		||||
target="/tmp/target"
 | 
			
		||||
mkdir -p ${target} >&2
 | 
			
		||||
echo -n "Mounting disks on temporary target '${target}'... "
 | 
			
		||||
mount /dev/vgx/root ${target} >&2
 | 
			
		||||
mkdir -p ${target}/boot >&2
 | 
			
		||||
chattr +i ${target}/boot >&2
 | 
			
		||||
mount ${target_disk}2 ${target}/boot >&2
 | 
			
		||||
mkdir -p ${target}/boot/efi >&2
 | 
			
		||||
chattr +i ${target}/boot/efi >&2
 | 
			
		||||
mount ${target_disk}1 ${target}/boot/efi >&2
 | 
			
		||||
mkdir -p ${target}/var/lib/ceph >&2
 | 
			
		||||
chattr +i ${target}/var/lib/ceph >&2
 | 
			
		||||
mount /dev/vgx/ceph ${target}/var/lib/ceph >&2
 | 
			
		||||
mkdir -p ${target}/var/lib/zookeeper >&2
 | 
			
		||||
chattr +i ${target}/var/lib/zookeeper >&2
 | 
			
		||||
mount /dev/vgx/zookeeper ${target}/var/lib/zookeeper >&2
 | 
			
		||||
mkdir -p ${target}/tmp >&2
 | 
			
		||||
chattr +i ${target}/tmp >&2
 | 
			
		||||
mount -t tmpfs tmpfs ${target}/tmp >&2
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
echo -n "Running debootstrap install... "
 | 
			
		||||
echo "Command: debootstrap --include=${inclpkglist} ${debrelease} ${target}/ ${debmirror}" >&2
 | 
			
		||||
debootstrap --include=${inclpkglist} ${debrelease} ${target}/ ${debmirror} >&2
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
echo -n "Adding non-free repository (firmware, etc.)... "
 | 
			
		||||
mkdir -p ${target}/etc/apt/sources.list.d/ >&2
 | 
			
		||||
echo "deb ${debmirror} ${debrelease} contrib non-free" | tee -a ${target}/etc/apt/sources.list >&2
 | 
			
		||||
chroot ${target} apt update >&2
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
echo -n "Installing supplemental packages... "
 | 
			
		||||
chroot ${target} apt install -y --no-install-recommends $( sed 's/,/ /g' <<<"${suppkglist}" ) >&2
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
# Determine the bypath name of the specified system disk
 | 
			
		||||
for disk in /dev/disk/by-path/*; do
 | 
			
		||||
    bypathlink="$( realpath ${disk} | awk -F'/' '{ print $NF }' )"
 | 
			
		||||
    enteredname="$( awk -F'/' '{ print $NF }' <<<"${target_disk}" )"
 | 
			
		||||
    if [[ ${bypathlink} == ${enteredname} ]]; then
 | 
			
		||||
        bypath_disk="${disk}"
 | 
			
		||||
    fi
 | 
			
		||||
done
 | 
			
		||||
 | 
			
		||||
echo -n "Adding fstab entries... "
 | 
			
		||||
echo "/dev/mapper/vgx-root / ext4 errors=remount-ro 0 1" | tee -a ${target}/etc/fstab >&2
 | 
			
		||||
echo "/dev/mapper/vgx-ceph /var/lib/ceph ext4 errors=remount-ro 0 2" | tee -a ${target}/etc/fstab >&2
 | 
			
		||||
echo "/dev/mapper/vgx-zookeeper /var/lib/zookeeper ext4 errors=remount-ro 0 2" | tee -a ${target}/etc/fstab >&2
 | 
			
		||||
echo "/dev/mapper/vgx-swap none swap sw 0 0" | tee -a ${target}/etc/fstab >&2
 | 
			
		||||
echo "${bypath_disk}-part2 /boot ext2 defaults 0 2" | tee -a ${target}/etc/fstab >&2
 | 
			
		||||
echo "${bypath_disk}-part1 /boot/efi vfat umask=0077 0 2" | tee -a ${target}/etc/fstab >&2
 | 
			
		||||
echo "tmpfs /tmp tmpfs defaults 0 0" | tee -a ${target}/etc/fstab >&2
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
seed_interfaces_segment() {
 | 
			
		||||
    # A seed install is always "dhcp-raw" since the provisioner is always a dedicated, access port
 | 
			
		||||
    target_interfaces_block="auto ${target_interface}\niface ${target_interface} inet dhcp\npost-up /etc/network/pvcprovisionerd.checkin.sh \$IFACE"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interactive_interfaces_segment() {
 | 
			
		||||
    case ${target_interfaces_is} in
 | 
			
		||||
        static-vlan)
 | 
			
		||||
            target_interfaces_block="auto ${vlan_interface}\niface ${vlan_interface} inet ${target_netformat}\n\tvlan_raw_device ${target_interface}\n\taddress ${formatted_ipaddr}\n\tnetmask ${formatted_netmask}\n\tgateway ${target_defgw}"
 | 
			
		||||
        ;;
 | 
			
		||||
        static-raw)
 | 
			
		||||
            target_interfaces_block="auto ${target_interface}\niface ${target_interface} inet ${target_netformat}\n\taddress ${formatted_ipaddr}\n\tnetmask ${formatted_netmask}\n\tgateway ${target_defgw}"
 | 
			
		||||
        ;;
 | 
			
		||||
        dhcp-vlan)
 | 
			
		||||
            target_interfaces_block="auto ${vlan_interface}\niface ${vlan_interface} inet ${target_netformat}\n\tvlan_raw_device${target_interface}"
 | 
			
		||||
        ;;
 | 
			
		||||
        dhcp-raw)
 | 
			
		||||
            target_interfaces_block="auto ${target_interface}\niface ${target_interface} inet ${target_netformat}"
 | 
			
		||||
        ;;
 | 
			
		||||
    esac
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
echo -n "Creating bootstrap interface segment... "
 | 
			
		||||
case ${install_option} in
 | 
			
		||||
    on)
 | 
			
		||||
        seed_interfaces_segment
 | 
			
		||||
    ;;
 | 
			
		||||
    *)
 | 
			
		||||
        interactive_interfaces_segment
 | 
			
		||||
    ;;
 | 
			
		||||
esac
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
echo -n "Adding bootstrap interface segment... "
 | 
			
		||||
echo -e "${target_interfaces_block}" | tee ${target}/etc/network/interfaces.d/${target_interface} >&2
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
case ${install_option} in
 | 
			
		||||
    on)
 | 
			
		||||
        echo -n "Creating bond interface segment... "
 | 
			
		||||
        bond_interfaces="$( ip -br link show | grep -E -o '^e[a-z]+[0-9]+[a-z0-9]*' | grep -v "^${target_interface}$" | tr '\n' ' ' )"
 | 
			
		||||
        bond_interfaces_block="auto bond0\niface bond0 inet manual\n\tbond-mode 802.3ad\n\tbond-slaves ${bond_interfaces}\n\tpost-up ip link set mtu 9000 dev \$IFACE"
 | 
			
		||||
        echo "done."
 | 
			
		||||
 | 
			
		||||
        echo -n "Adding bond interface segment... "
 | 
			
		||||
        echo -e "${bond_interfaces_block}" | tee ${target}/etc/network/interfaces.d/bond0 >&2
 | 
			
		||||
        echo "done."
 | 
			
		||||
 | 
			
		||||
        echo -n "Adding bootstrap interface post-up checkin script... "
 | 
			
		||||
        cat <<EOF | tee ${target}/etc/network/pvcprovisionerd.checkin.sh >&2
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
target_interface=\${1}
 | 
			
		||||
pvcbootstrapd_checkin_uri="${pvcbootstrapd_checkin_uri}"
 | 
			
		||||
macaddr=\$( ip -br link show \${target_interface} | awk '{ print \$3 }' )
 | 
			
		||||
ipaddr=\$( ip -br address show \${target_interface} | awk '{ print \$3 }' | awk -F '/' '{ print \$1 }' )
 | 
			
		||||
bmc_macaddr=\$( ipmitool lan print | grep 'MAC Address  ' | awk '{ print $NF }' )
 | 
			
		||||
bmc_ipaddr=\$( ipmitool lan print | grep 'IP Address  ' | awk '{ print $NF }' )
 | 
			
		||||
if [[ -f /etc/pvc-install.pvcbootstrapd_completed ]]; then
 | 
			
		||||
    # The third boot, when all pvcprovisionerd plugins have been run (this script will henceforth do nothing)
 | 
			
		||||
    action="system-boot_bootstrap-completed"
 | 
			
		||||
elif [[ -f /etc/pvc-install.base && -f /etc/pvc-install.pvc ]]; then
 | 
			
		||||
    # The second boot, when Ansible has been run and plugins running
 | 
			
		||||
    action="system-boot_ansible-completed"
 | 
			
		||||
    touch /etc/pvc-install.pvcbootstrapd_completed
 | 
			
		||||
else
 | 
			
		||||
    # The first boot, when Ansible has not been run yet
 | 
			
		||||
    action="system-boot_initial"
 | 
			
		||||
fi
 | 
			
		||||
curl -X POST \
 | 
			
		||||
    -H "Content-Type: application/json" \
 | 
			
		||||
    -d "{\"action\":\"\${action}\",\"macaddr\":\"\${macaddr}\",\"ipaddr\":\"\${ipaddr}\",\"hostname\":\"\$( hostname -s )\",\"bmc_macaddr\":\"\${bmc_macaddr}\",\"bmc_ipaddr\":\"\${bmc_ipaddr}\"}" \
 | 
			
		||||
    \${pvcbootstrapd_checkin_uri}
 | 
			
		||||
 | 
			
		||||
if [[ -f /etc/pvc-install.pvcbootstrapd_completed ]]; then
 | 
			
		||||
    # Clean up the bootstrap interface and this script
 | 
			
		||||
    rm /etc/network/interfaces.d/\${target_interface}
 | 
			
		||||
    rm \$0
 | 
			
		||||
    exit 0
 | 
			
		||||
fi
 | 
			
		||||
EOF
 | 
			
		||||
        chmod +x ${target}/etc/network/pvcprovisionerd.checkin.sh
 | 
			
		||||
        echo "done."
 | 
			
		||||
    ;;
 | 
			
		||||
    *)
 | 
			
		||||
        # noop
 | 
			
		||||
        true
 | 
			
		||||
    ;;
 | 
			
		||||
esac
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
echo -n "Setting temporary 'root' password... "
 | 
			
		||||
echo "root:${root_password}" | chroot ${target} chpasswd >&2
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
echo -n "Adding deployment user... "
 | 
			
		||||
mv ${target}/home ${target}/var/home >&2
 | 
			
		||||
chroot ${target} useradd -u 200 -d /var/home/${target_deploy_user} -m -s /bin/bash -g operator -G sudo ${target_deploy_user} >&2
 | 
			
		||||
chroot ${target} mkdir -p /var/home/${target_deploy_user}/.ssh
 | 
			
		||||
if [[ -n ${target_keys_path} ]]; then
 | 
			
		||||
    case ${target_keys_method} in
 | 
			
		||||
        wget)
 | 
			
		||||
            wget -O ${target}/var/home/${target_deploy_user}/.ssh/authorized_keys ${target_keys_path}
 | 
			
		||||
        ;;
 | 
			
		||||
        tftp)
 | 
			
		||||
            tftp -m binary "${seed_host}" -c get "${target_keys_path}" ${target}/var/home/${target_deploy_user}/.ssh/authorized_keys
 | 
			
		||||
        ;;
 | 
			
		||||
    esac
 | 
			
		||||
    chroot ${target} chmod 0600 /var/home/${target_deploy_user}/.ssh/authorized_keys
 | 
			
		||||
    chroot ${target} chown -R ${target_deploy_user}:operator /var/home/${target_deploy_user}
 | 
			
		||||
else
 | 
			
		||||
    echo "${target_deploy_user}:${target_password}" | chroot ${target} chpasswd >&2
 | 
			
		||||
fi
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
echo -n "Setting NOPASSWD for sudo group... "
 | 
			
		||||
sed -i 's/^%sudo\tALL=(ALL:ALL) ALL/%sudo\tALL=(ALL:ALL) NOPASSWD: ALL/' ${target}/etc/sudoers
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
echo -n "Setting /etc/issue generator... "
 | 
			
		||||
mkdir -p ${target}/etc/network/if-up.d >&2
 | 
			
		||||
echo -e "#!/bin/sh
 | 
			
		||||
IP=\"\$( ip -4 addr show dev ${target_interface} | grep inet | awk '{ print \$2 }' | head -1 )\"
 | 
			
		||||
cat <<EOF >/etc/issue
 | 
			
		||||
Debian GNU/Linux 10 \\\\n \\\\l
 | 
			
		||||
 | 
			
		||||
Bootstrap interface IP address: \$IP
 | 
			
		||||
 | 
			
		||||
EOF" | tee ${target}/etc/network/if-up.d/issue-gen >&2
 | 
			
		||||
chmod +x ${target}/etc/network/if-up.d/issue-gen 1>&2
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
echo -n "Generating host rsa and ed25519 keys... "
 | 
			
		||||
rm ${target}/etc/ssh/ssh_host_*_key* >&2
 | 
			
		||||
chroot ${target} ssh-keygen -t rsa -N "" -f /etc/ssh/ssh_host_rsa_key >&2
 | 
			
		||||
chroot ${target} ssh-keygen -t ed25519 -N "" -f /etc/ssh/ssh_host_ed25519_key >&2
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
echo -n "Setting hostname... "
 | 
			
		||||
echo "${target_hostname}" | tee ${target}/etc/hostname >&2
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
echo -n "Setting resolv.conf... "
 | 
			
		||||
echo "nameserver 8.8.8.8" | tee ${target}/etc/resolv.conf >&2
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
echo -n "Installing GRUB bootloader... "
 | 
			
		||||
mount --bind /dev ${target}/dev >&2
 | 
			
		||||
mount --bind /dev/pts ${target}/dev/pts >&2
 | 
			
		||||
mount --bind /proc ${target}/proc >&2
 | 
			
		||||
mount --bind /sys ${target}/sys >&2
 | 
			
		||||
mount --bind /run ${target}/run >&2
 | 
			
		||||
if [[ -d /sys/firmware/efi ]]; then
 | 
			
		||||
    bios_target="x86_64-efi"
 | 
			
		||||
else
 | 
			
		||||
    bios_target="i386-pc"
 | 
			
		||||
fi
 | 
			
		||||
cat <<EOF | tee ${target}/etc/default/grub >&2
 | 
			
		||||
GRUB_DEFAULT=0
 | 
			
		||||
GRUB_TIMEOUT=5
 | 
			
		||||
GRUB_DISTRIBUTOR="Parallel Virtual Cluster (PVC) - Debian"
 | 
			
		||||
GRUB_CMDLINE_LINUX="console=hvc0 console=tty0 console=ttyS0,115200"
 | 
			
		||||
GRUB_TERMINAL_INPUT="console serial"
 | 
			
		||||
GRUB_TERMINAL_OUTPUT="gfxterm serial"
 | 
			
		||||
GRUB_SERIAL_COMMAND="serial --unit=0 --unit=1 --speed=115200"
 | 
			
		||||
EOF
 | 
			
		||||
chroot ${target} grub-install --force --target=${bios_target} ${target_disk} >&2
 | 
			
		||||
chroot ${target} grub-mkconfig -o /boot/grub/grub.cfg >&2
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
seed_postinst() {
 | 
			
		||||
    cleanup
 | 
			
		||||
    echo "Temporary root password: ${root_password}"
 | 
			
		||||
    seed_checkin end
 | 
			
		||||
 | 
			
		||||
    echo -n "Rebooting in 10 seconds..."
 | 
			
		||||
    i=10
 | 
			
		||||
    while [[ ${i} -gt 0 ]]; do
 | 
			
		||||
        sleep 1
 | 
			
		||||
        i=$(( ${1} - 1 ))
 | 
			
		||||
        echo -n "."
 | 
			
		||||
    done
 | 
			
		||||
    echo
 | 
			
		||||
    reboot
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interactive_postinst() {
 | 
			
		||||
    set +o errexit
 | 
			
		||||
    echo
 | 
			
		||||
    echo -n "Edit the /etc/network/interfaces file in the target before completing setup? If you plan to use bonding, it is prudent to set this up in basic form now! [y/N] "
 | 
			
		||||
    read edit_ifaces
 | 
			
		||||
    if [[ ${edit_ifaces} == 'y' || ${edit_ifaces} == 'Y' ]]; then
 | 
			
		||||
        vim ${target}/etc/network/interfaces
 | 
			
		||||
    fi
 | 
			
		||||
    echo
 | 
			
		||||
 | 
			
		||||
    echo -n "Launch a chroot shell in the target environment? [y/N] "
 | 
			
		||||
    read launch_chroot
 | 
			
		||||
    if [[ ${launch_chroot} == 'y' || ${edit_ifaces} == 'Y' ]]; then
 | 
			
		||||
        echo "Type 'exit' or Ctrl+D to exit chroot."
 | 
			
		||||
        chroot ${target} /bin/bash
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    cleanup
 | 
			
		||||
 | 
			
		||||
    echo "-------------------------------------------------------------------------------------"
 | 
			
		||||
    echo "| PVC node installation finished. Next steps:                                       |"
 | 
			
		||||
    echo "| 1. Press <enter> to reboot the system.                                            |"
 | 
			
		||||
    echo "| 2. Boot the system verify SSH access (IP shown on login screen).                  |"
 | 
			
		||||
    echo "| 3. Proceed with system deployment via PVC Ansible.                                |"
 | 
			
		||||
    echo "|                                                                                   |"
 | 
			
		||||
    echo "| The INSECURE temporary root password if the system will not boot is: ${root_password}     |"
 | 
			
		||||
    echo "-------------------------------------------------------------------------------------"
 | 
			
		||||
    echo
 | 
			
		||||
    read
 | 
			
		||||
 | 
			
		||||
    reboot
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
case ${install_option} in
 | 
			
		||||
    on)
 | 
			
		||||
        seed_postinst
 | 
			
		||||
    ;;
 | 
			
		||||
    *)
 | 
			
		||||
        interactive_postinst
 | 
			
		||||
    ;;
 | 
			
		||||
esac
 | 
			
		||||
							
								
								
									
										1
									
								
								install.sh
									
									
									
									
									
										Symbolic link
									
								
							
							
						
						
									
										1
									
								
								install.sh
									
									
									
									
									
										Symbolic link
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
templates/install.sh
 | 
			
		||||
							
								
								
									
										3
									
								
								templates/2000-remove-root-pw.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										3
									
								
								templates/2000-remove-root-pw.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,3 @@
 | 
			
		||||
#!/bin/sh
 | 
			
		||||
echo "I: remove root password"
 | 
			
		||||
passwd --delete root
 | 
			
		||||
							
								
								
									
										69
									
								
								templates/9990-initramfs-tools.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										69
									
								
								templates/9990-initramfs-tools.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,69 @@
 | 
			
		||||
#!/bin/sh
 | 
			
		||||
 | 
			
		||||
#set -e
 | 
			
		||||
 | 
			
		||||
log_wait_msg ()
 | 
			
		||||
{
 | 
			
		||||
	# Print a message and wait for enter
 | 
			
		||||
	if [ -x /bin/plymouth ] && plymouth --ping
 | 
			
		||||
	then
 | 
			
		||||
		plymouth message --text="$@"
 | 
			
		||||
		plymouth watch-keystroke | read nunya
 | 
			
		||||
	fi
 | 
			
		||||
 | 
			
		||||
	_log_msg "Waiting: ${@} ... \n"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Override maybe_break from scripts/functions
 | 
			
		||||
maybe_break()
 | 
			
		||||
{
 | 
			
		||||
	if [ "${break}" = "$1" ]; then
 | 
			
		||||
		# Call original panic
 | 
			
		||||
		. /scripts/functions
 | 
			
		||||
		panic "Spawning shell within the initramfs"
 | 
			
		||||
	fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Override panic from scripts/functions
 | 
			
		||||
panic()
 | 
			
		||||
{
 | 
			
		||||
	for _PARAMETER in ${LIVE_BOOT_CMDLINE}
 | 
			
		||||
	do
 | 
			
		||||
		case "${_PARAMETER}" in
 | 
			
		||||
			panic=*)
 | 
			
		||||
				panic="${_PARAMETER#*panic=}"
 | 
			
		||||
				;;
 | 
			
		||||
		esac
 | 
			
		||||
	done
 | 
			
		||||
 | 
			
		||||
	DEB_1="\033[1;31m .''\`.  \033[0m"
 | 
			
		||||
	DEB_2="\033[1;31m: :'  : \033[0m"
 | 
			
		||||
	DEB_3="\033[1;31m\`. \`'\`  \033[0m"
 | 
			
		||||
	DEB_4="\033[1;31m  \`-    \033[0m"
 | 
			
		||||
 | 
			
		||||
	LIVELOG="\033[1;37m/boot.log\033[0m"
 | 
			
		||||
	DEBUG="\033[1;37mdebug\033[0m"
 | 
			
		||||
 | 
			
		||||
	# Reset redirections to avoid buffering
 | 
			
		||||
	exec 1>&6 6>&-
 | 
			
		||||
	exec 2>&7 7>&-
 | 
			
		||||
	kill ${tailpid}
 | 
			
		||||
 | 
			
		||||
	printf "\n\n"
 | 
			
		||||
	printf "  \033[1;37mBOOT FAILED!\033[0m\n"
 | 
			
		||||
	printf "\n"
 | 
			
		||||
	printf "  The PVC installer image failed to boot.\n\n"
 | 
			
		||||
	printf "The error message was:\n\n    "
 | 
			
		||||
	printf "  $@\n\n"
 | 
			
		||||
 | 
			
		||||
    # Reboot system
 | 
			
		||||
    printf "System will reboot in 30 seconds. Press any key to spawn a shell instead.\n"
 | 
			
		||||
    if ! read -t 30; then
 | 
			
		||||
        sleep 30
 | 
			
		||||
        reboot -f
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
	# Call original panic
 | 
			
		||||
	. /scripts/functions
 | 
			
		||||
    panic "$@"
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										24
									
								
								templates/boot.pxe
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								templates/boot.pxe
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
			
		||||
#!ipxe
 | 
			
		||||
 | 
			
		||||
# Set global variables
 | 
			
		||||
set root-url tftp://${next-server}
 | 
			
		||||
set kernel vmlinuz
 | 
			
		||||
set initrd initrd.img
 | 
			
		||||
 | 
			
		||||
# Set kernel command line parameters
 | 
			
		||||
set imgargs-base vga=normal nomodeset boot=live components ethdevice-timeout=600 timezone=America/Toronto fetch=${root-url}/filesystem.squashfs username=root
 | 
			
		||||
set imgargs-pvcinstall pvcinstall.preseed=on pvcinstall.seed_host=${next-server} pvcinstall.seed_file=/host/mac-${mac:hexraw}.preseed
 | 
			
		||||
 | 
			
		||||
# Load per-host kernel command line parameters (should contain ${imgargs-host} if present)
 | 
			
		||||
chain --autofree ${root-url}/host/mac-${mac:hexraw}.ipxe ||
 | 
			
		||||
 | 
			
		||||
# Set default menu options
 | 
			
		||||
set menu-default pvc-installer
 | 
			
		||||
set submenu-default pvc-installer
 | 
			
		||||
 | 
			
		||||
# PVC installer menu option
 | 
			
		||||
:pvc-installer
 | 
			
		||||
kernel ${root-url}/vmlinuz
 | 
			
		||||
initrd ${root-url}/initrd.img
 | 
			
		||||
imgargs vmlinuz ${imgargs-host} ${imgargs-base} ${imgargs-pvcinstall}
 | 
			
		||||
boot
 | 
			
		||||
							
								
								
									
										1
									
								
								templates/firmware.list.chroot
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								templates/firmware.list.chroot
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
firmware-bnx2 firmware-bnx2x
 | 
			
		||||
							
								
								
									
										3
									
								
								templates/getty-override.conf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								templates/getty-override.conf
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
			
		||||
[Service]
 | 
			
		||||
ExecStart=
 | 
			
		||||
ExecStart=-/sbin/agetty -o '-p -- \\u' --autologin root --noclear %I $TERM
 | 
			
		||||
							
								
								
									
										1
									
								
								templates/hostname
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								templates/hostname
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
pvc-live-installer
 | 
			
		||||
							
								
								
									
										892
									
								
								templates/install.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										892
									
								
								templates/install.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,892 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
 | 
			
		||||
logfile="/tmp/pvc-install.log"
 | 
			
		||||
lockfile="/run/pvc-install.lock"
 | 
			
		||||
 | 
			
		||||
if [[ $( whoami ) != "root" ]]; then
 | 
			
		||||
    echo "STOP! This script is designed to run as root within the installer only!"
 | 
			
		||||
    echo "To build a PVC installer ISO file, use './buildiso.sh'."
 | 
			
		||||
    echo "To build a PVC installer PXE root, use './buildpxe.sh'."
 | 
			
		||||
    exit 1
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
echo
 | 
			
		||||
active_ttys=( $( w | grep "^root" | awk '{ print $2 }' ) )
 | 
			
		||||
echo "Active TTYs: ${active_ttys[@]}"
 | 
			
		||||
this_tty=$( tty | sed -e "s:/dev/::" )
 | 
			
		||||
echo "This TTY: ${this_tty}"
 | 
			
		||||
echo
 | 
			
		||||
 | 
			
		||||
if [[ ${#active_ttys} -gt 1 ]]; then
 | 
			
		||||
    if [[ "${active_ttys[@]}" =~ "ttyS" ]]; then
 | 
			
		||||
        if grep -q -E -o "tty[0-9]+" <<<"${this_tty}"; then
 | 
			
		||||
            echo "Found more than one TTY and at least one serial TTY!"
 | 
			
		||||
            echo -n "If you wish to run the installer on this graphical TTY instead of the serial TTY, press enter within 15 seconds... "
 | 
			
		||||
            if ! read -t 15; then
 | 
			
		||||
                echo "timeout."
 | 
			
		||||
                exit 0
 | 
			
		||||
            fi
 | 
			
		||||
        else
 | 
			
		||||
            echo "Found more than one TTY!"
 | 
			
		||||
            echo -n "Waiting for other TTYs to time out... "
 | 
			
		||||
            sleep $(( 16 + $( grep -E -o '[0-9]+' <<<"${this_tty}" ) ))
 | 
			
		||||
            echo "done."
 | 
			
		||||
        fi
 | 
			
		||||
    else
 | 
			
		||||
        echo "Found more than one graphical TTY!"
 | 
			
		||||
        echo -n "If you wish to run the installer on this graphical TTY, press enter within 60 seconds... "
 | 
			
		||||
        if ! read -t 60; then
 | 
			
		||||
            echo "timeout."
 | 
			
		||||
            echo "To launch the installer again on this TTY, run '/install.sh'."
 | 
			
		||||
            exit 0
 | 
			
		||||
        fi
 | 
			
		||||
    fi
 | 
			
		||||
fi
 | 
			
		||||
if [[ -f ${lockfile} ]]; then
 | 
			
		||||
    echo "Aborting installer due to lockfile presence: $( cat ${lockfile} )."
 | 
			
		||||
    exit 0
 | 
			
		||||
fi
 | 
			
		||||
printf "PID $$ on TTY ${this_tty}" > ${lockfile}
 | 
			
		||||
echo
 | 
			
		||||
 | 
			
		||||
iso_name="XXDATEXX"
 | 
			
		||||
target_deploy_user="XXDEPLOYUSERXX"
 | 
			
		||||
 | 
			
		||||
supported_debrelease="buster bullseye"
 | 
			
		||||
default_debrelease="buster"
 | 
			
		||||
default_debmirror="http://debian.mirror.rafal.ca/debian"
 | 
			
		||||
 | 
			
		||||
inclpkglist="lvm2,parted,gdisk,grub-pc,grub-efi-amd64,linux-image-amd64,sudo,vim,gpg,gpg-agent,aptitude,openssh-server,vlan,ifenslave,python3,ca-certificates,curl"
 | 
			
		||||
suppkglist="firmware-linux,firmware-linux-nonfree,firmware-bnx2,firmware-bnx2x,ntp"
 | 
			
		||||
 | 
			
		||||
# DANGER - THIS PASSWORD IS PUBLIC
 | 
			
		||||
# It should be used ONLY immediately after booting the PVC node in a SECURE environment
 | 
			
		||||
# to facilitate troubleshooting of a failed boot. It should NOT be exposed to the Internet,
 | 
			
		||||
# and it should NOT be left in place after system configuration. The PVC Ansible deployment
 | 
			
		||||
# roles will overwrite it by default during configuration.
 | 
			
		||||
root_password="hCb1y2PF"
 | 
			
		||||
 | 
			
		||||
# Respawn function
 | 
			
		||||
respawn() (
 | 
			
		||||
    echo "Respawning..."
 | 
			
		||||
    $0 & disown
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
# Checkin function
 | 
			
		||||
seed_checkin() (
 | 
			
		||||
    case ${1} in
 | 
			
		||||
        start)
 | 
			
		||||
            action="install-start"
 | 
			
		||||
        ;;
 | 
			
		||||
        end)
 | 
			
		||||
            action="install-complete"
 | 
			
		||||
        ;;
 | 
			
		||||
    esac
 | 
			
		||||
    macaddr=$( ip -br link show ${target_interface} | awk '{ print $3 }' )
 | 
			
		||||
    ipaddr=$( ip -br address show ${target_interface} | awk '{ print $3 }' | awk -F '/' '{ print $1 }' )
 | 
			
		||||
    curl -X POST \
 | 
			
		||||
        -H "Content-Type: application/json" \
 | 
			
		||||
        -d "{\"action\":\"${action}\",\"macaddr\":\"${macaddr}\",\"ipaddr\":\"${ipaddr}\",\"hostname\":\"${target_hostname}\",\"bmc_macaddr\":\"${bmc_macaddr}\",\"bmc_ipaddr\":\"${bmc_ipaddr}\"}" \
 | 
			
		||||
        ${pvcbootstrapd_checkin_uri}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
# Obtain the preseed options from the kernel command line
 | 
			
		||||
install_option=""
 | 
			
		||||
seed_host=""
 | 
			
		||||
seed_file=""
 | 
			
		||||
kernel_cmdline=( $( cat /proc/cmdline ) )
 | 
			
		||||
for option in ${kernel_cmdline[@]}; do
 | 
			
		||||
    case ${option} in
 | 
			
		||||
        pvcinstall.preseed=*)
 | 
			
		||||
            install_option=${option#pvcinstall.preseed=}
 | 
			
		||||
        ;;
 | 
			
		||||
        pvcinstall.seed_host=*)
 | 
			
		||||
            seed_host=${option#pvcinstall.seed_host=}
 | 
			
		||||
        ;;
 | 
			
		||||
        pvcinstall.seed_file=*)
 | 
			
		||||
            seed_file=${option#pvcinstall.seed_file=}
 | 
			
		||||
        ;;
 | 
			
		||||
    esac
 | 
			
		||||
done
 | 
			
		||||
 | 
			
		||||
seed_config() {
 | 
			
		||||
    # Get IPMI BMC MAC for checkings
 | 
			
		||||
    bmc_macaddr="$( ipmitool lan print | grep 'MAC Address  ' | awk '{ print $NF }' )"
 | 
			
		||||
    bmc_ipaddr="$( ipmitool lan print | grep 'IP Address  ' | awk '{ print $NF }' )"
 | 
			
		||||
 | 
			
		||||
    # Perform DHCP on all interfaces to come online
 | 
			
		||||
    for interface in $( ip address | grep '^[0-9]' | grep 'eno\|enp\|ens\|wlp' | awk '{ print $2 }' | tr -d ':' ); do
 | 
			
		||||
        ip link set ${interface} up
 | 
			
		||||
        pgrep dhclient || dhclient ${interface}
 | 
			
		||||
    done
 | 
			
		||||
 | 
			
		||||
    # Fetch the seed config
 | 
			
		||||
    tftp -m binary "${seed_host}" -c get "${seed_file}" /tmp/install.seed
 | 
			
		||||
 | 
			
		||||
    . /tmp/install.seed || exit 1
 | 
			
		||||
 | 
			
		||||
    # Handle the target interface
 | 
			
		||||
    target_route="$( ip route show to match ${seed_host} | grep 'scope link' )"
 | 
			
		||||
    target_interface="$( grep -E -o 'e[a-z]+[0-9]+[a-z0-9]*' <<<"${target_route}" )"
 | 
			
		||||
 | 
			
		||||
    # Handle the target disk
 | 
			
		||||
    if [[ -n ${target_disk_path} ]]; then
 | 
			
		||||
        target_disk="$( realpath ${target_disk_path} )"
 | 
			
		||||
    else
 | 
			
		||||
        # Find the (first) disk with the given model
 | 
			
		||||
        for disk in /dev/sd?; do
 | 
			
		||||
            disk_model="$( fdisk -l ${disk} | grep 'Disk model:' | sed 's/Disk model: //g' )"
 | 
			
		||||
            if [[ ${disk_model} == ${target_disk_model} ]]; then
 | 
			
		||||
                target_disk="${disk}"
 | 
			
		||||
                break
 | 
			
		||||
            fi
 | 
			
		||||
        done
 | 
			
		||||
    fi
 | 
			
		||||
    if [[ ! -b ${target_disk} ]]; then
 | 
			
		||||
        echo "Invalid disk or disk not found!"
 | 
			
		||||
        exit 1
 | 
			
		||||
    fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interactive_config() {
 | 
			
		||||
    clear
 | 
			
		||||
 | 
			
		||||
    echo "--------------------------------------------------------"
 | 
			
		||||
    echo "| PVC Node installer (${iso_name}) |"
 | 
			
		||||
    echo "--------------------------------------------------------"
 | 
			
		||||
    echo
 | 
			
		||||
    echo "This LiveCD will install a PVC node base system ready for bootstrapping with 'pvc-ansible'."
 | 
			
		||||
    echo
 | 
			
		||||
    echo "* NOTE: If you make a mistake and need to restart the installer while answering"
 | 
			
		||||
    echo "        the questions below, you may do so by typing ^C to cancel the script,"
 | 
			
		||||
    echo "        then re-running it by calling /install.sh in the resulting shell."
 | 
			
		||||
    echo
 | 
			
		||||
 | 
			
		||||
    echo "1) Please enter a fully-qualified hostname for the system. This should match the hostname"
 | 
			
		||||
    echo "in the 'pvc-ansible' inventory."
 | 
			
		||||
    while [[ -z ${target_hostname} ]]; do
 | 
			
		||||
        echo
 | 
			
		||||
        echo -n "> "
 | 
			
		||||
        read target_hostname
 | 
			
		||||
        if [[ -z ${target_hostname} ]]; then
 | 
			
		||||
            echo
 | 
			
		||||
            echo "Please enter a hostname."
 | 
			
		||||
            continue
 | 
			
		||||
        fi
 | 
			
		||||
        echo
 | 
			
		||||
    done
 | 
			
		||||
 | 
			
		||||
    disks="$(
 | 
			
		||||
        for disk in /dev/sd? /dev/nvme?n?; do
 | 
			
		||||
            if [[ ! -b ${disk} ]]; then
 | 
			
		||||
                continue
 | 
			
		||||
            fi
 | 
			
		||||
            disk_data="$( fdisk -l ${disk} 2>/dev/null )"
 | 
			
		||||
            echo -n "${disk}"
 | 
			
		||||
            echo -en "\t$( grep "^Disk model:" <<<"${disk_data}" | awk '{ $1=""; print $0 }' )"
 | 
			
		||||
            echo -en "  $( grep "^Disk ${disk}:" <<<"${disk_data}" | awk '{ $1=""; $2="size:"; print $0 }' )"
 | 
			
		||||
            echo
 | 
			
		||||
        done
 | 
			
		||||
    )"
 | 
			
		||||
 | 
			
		||||
    echo "2) Please enter the disk to install the PVC base system to. This disk will be"
 | 
			
		||||
    echo "wiped, an LVM PV created on it, and the system installed to this LVM."
 | 
			
		||||
    echo "* NOTE: PVC requires a disk of at least 30GB to be installed to, and 100GB is the"
 | 
			
		||||
    echo "recommended minimum size for optimal production partition sizes."
 | 
			
		||||
    echo "* NOTE: For optimal performance, this disk should be high-performance flash (SSD, etc.)."
 | 
			
		||||
    echo "* NOTE: This disk should be a RAID-1 volume configured in hardware, or a durable storage"
 | 
			
		||||
    echo "device, maximum redundancy and resiliency."
 | 
			
		||||
    echo
 | 
			
		||||
    echo "Available disks:"
 | 
			
		||||
    echo
 | 
			
		||||
    echo -e "$( sed 's/\(.*\)/  \1/' <<<"${disks[@]}" )"
 | 
			
		||||
    while [[ ! -b ${target_disk} ]]; do
 | 
			
		||||
        echo
 | 
			
		||||
        echo -n "> "
 | 
			
		||||
        read target_disk
 | 
			
		||||
        if [[ ! -b ${target_disk} ]]; then
 | 
			
		||||
            echo
 | 
			
		||||
            echo "Please enter a valid target disk."
 | 
			
		||||
            continue
 | 
			
		||||
        fi
 | 
			
		||||
        blockdev_size_gbytes="$(( $( blockdev --getsize64 ${target_disk} ) / 1024 / 1024 / 1024 - 1))"
 | 
			
		||||
        if [[ ${blockdev_size_gbytes} -lt 30 ]]; then
 | 
			
		||||
            target_disk=""
 | 
			
		||||
            echo
 | 
			
		||||
            echo "The specified disk is too small (<30 GB) to use as a PVC system disk."
 | 
			
		||||
            echo "Please choose an alternative disk."
 | 
			
		||||
            continue
 | 
			
		||||
        fi
 | 
			
		||||
        echo
 | 
			
		||||
    done
 | 
			
		||||
 | 
			
		||||
    for interface in $( ip address | grep '^[0-9]' | grep 'eno\|enp\|ens\|wlp' | awk '{ print $2 }' | tr -d ':' ); do
 | 
			
		||||
        ip link set ${interface} up
 | 
			
		||||
    done
 | 
			
		||||
    sleep 2
 | 
			
		||||
    interfaces="$(
 | 
			
		||||
        ip address | grep '^[0-9]' | grep 'eno\|enp\|ens\|wlp' | awk '{ print $2"\t"$3 }' | tr -d ':'
 | 
			
		||||
    )"
 | 
			
		||||
    echo "3a) Please enter the primary network interface for external connectivity. If"
 | 
			
		||||
    echo "no entries are shown here, ensure a cable is connected, then restart the"
 | 
			
		||||
    echo "installer with ^C and '/install.sh'."
 | 
			
		||||
    echo
 | 
			
		||||
    echo "Available interfaces:"
 | 
			
		||||
    echo
 | 
			
		||||
    echo -e "$( sed 's/\(.*\)/  \1/' <<<"${interfaces[@]}" )"
 | 
			
		||||
    while [[ -z ${target_interface} ]]; do
 | 
			
		||||
        echo
 | 
			
		||||
        echo -n "> "
 | 
			
		||||
        read target_interface
 | 
			
		||||
        if [[ -z ${target_interface} ]]; then
 | 
			
		||||
            echo
 | 
			
		||||
            echo "Please enter a valid interface."
 | 
			
		||||
            continue
 | 
			
		||||
        fi
 | 
			
		||||
        if ! grep -qw "${target_interface}" <<<"${interfaces[@]}"; then
 | 
			
		||||
            target_interface=""
 | 
			
		||||
            echo
 | 
			
		||||
            echo "Please enter a valid interface."
 | 
			
		||||
            continue
 | 
			
		||||
        fi
 | 
			
		||||
        echo
 | 
			
		||||
    done
 | 
			
		||||
 | 
			
		||||
    echo -n "3b) Is a tagged vLAN required for the primary network interface? [y/N] "
 | 
			
		||||
    read vlans_req
 | 
			
		||||
    if [[ ${vlans_req} == 'y' || ${vlans_req} == 'Y' ]]; then
 | 
			
		||||
        echo
 | 
			
		||||
        echo "Please enter the vLAN ID for the interface."
 | 
			
		||||
        while [[ -z ${vlan_id} ]]; do
 | 
			
		||||
            echo
 | 
			
		||||
            echo -n "> "
 | 
			
		||||
            read vlan_id
 | 
			
		||||
            if [[ -z ${vlan_id} ]]; then
 | 
			
		||||
                echo
 | 
			
		||||
                echo "Please enter a numeric vLAN ID."
 | 
			
		||||
                continue
 | 
			
		||||
            fi
 | 
			
		||||
        done
 | 
			
		||||
        echo
 | 
			
		||||
    else
 | 
			
		||||
        vlan_id=""
 | 
			
		||||
        echo
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    echo "3c) Please enter the IP address, in CIDR format [X.X.X.X/YY], of the primary"
 | 
			
		||||
    echo "network interface. Leave blank for DHCP configuration of the interface on boot."
 | 
			
		||||
    echo
 | 
			
		||||
    echo -n "> "
 | 
			
		||||
    read target_ipaddr
 | 
			
		||||
    if [[ -n ${target_ipaddr} ]]; then
 | 
			
		||||
        target_netformat="static"
 | 
			
		||||
        echo
 | 
			
		||||
        echo "3d) Please enter the default gateway IP address of the primary"
 | 
			
		||||
        echo "network interface."
 | 
			
		||||
        while [[ -z ${target_defgw} ]]; do
 | 
			
		||||
            echo
 | 
			
		||||
            echo -n "> "
 | 
			
		||||
            read target_defgw
 | 
			
		||||
            if [[ -z ${target_defgw} ]]; then
 | 
			
		||||
                echo
 | 
			
		||||
                echo "Please enter a default gateway; the installer requires Internet access."
 | 
			
		||||
                continue
 | 
			
		||||
            fi
 | 
			
		||||
            echo
 | 
			
		||||
        done
 | 
			
		||||
    else
 | 
			
		||||
        target_netformat="dhcp"
 | 
			
		||||
        echo
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    echo -n "Bringing up primary network interface in ${target_netformat} mode... "
 | 
			
		||||
    case ${target_netformat} in
 | 
			
		||||
        'static')
 | 
			
		||||
            if [[ -n ${vlan_id} ]]; then
 | 
			
		||||
                modprobe 8021q >&2
 | 
			
		||||
                vconfig add ${target_interface} ${vlan_id} >&2
 | 
			
		||||
                vlan_interface=${target_interface}.${vlan_id}
 | 
			
		||||
                ip link set ${target_interface} up >&2 || true
 | 
			
		||||
                ip link set ${vlan_interface} up >&2 || true
 | 
			
		||||
                ip address add ${target_ipaddr} dev ${vlan_interface} >&2 || true
 | 
			
		||||
                ip route add default via ${target_defgw} >&2 || true
 | 
			
		||||
                formatted_ipaddr="$( sipcalc ${target_ipaddr} | grep -v '(' | awk '/Host address/{ print $NF }' )"
 | 
			
		||||
                formatted_netmask="$( sipcalc ${target_ipaddr} | grep -v '(' | awk '/Network mask/{ print $NF }' )"
 | 
			
		||||
                real_interface="${vlan_interface}"
 | 
			
		||||
                target_interfaces_is="static-vlan"
 | 
			
		||||
            else
 | 
			
		||||
                ip link set ${target_interface} up >&2 || true
 | 
			
		||||
                ip address add ${target_ipaddr} dev ${target_interface} >&2 || true
 | 
			
		||||
                ip route add default via ${target_defgw} >&2 || true
 | 
			
		||||
                formatted_ipaddr="$( sipcalc ${target_ipaddr} | grep -v '(' | awk '/Host address/{ print $NF }' )"
 | 
			
		||||
                formatted_netmask="$( sipcalc ${target_ipaddr} | grep -v '(' | awk '/Network mask/{ print $NF }' )"
 | 
			
		||||
                real_interface="${target_interface}"
 | 
			
		||||
                target_interfaces_is="static-raw"
 | 
			
		||||
            fi
 | 
			
		||||
            cat <<EOF >/etc/resolv.conf
 | 
			
		||||
nameserver 8.8.8.8
 | 
			
		||||
EOF
 | 
			
		||||
        ;;
 | 
			
		||||
        'dhcp')
 | 
			
		||||
            if [[ -n ${vlan_id} ]]; then
 | 
			
		||||
                modprobe 8021q >&2
 | 
			
		||||
                vconfig add ${target_interface} ${vlan_id} &>/dev/null
 | 
			
		||||
                vlan_interface=${target_interface}.${vlan_id}
 | 
			
		||||
                dhclient ${vlan_interface} >&2
 | 
			
		||||
                real_interface="${vlan_interface}"
 | 
			
		||||
                target_interfaces_is="dhcp-vlan"
 | 
			
		||||
            else
 | 
			
		||||
                dhclient ${target_interface} >&2
 | 
			
		||||
                real_interface="${target_interface}"
 | 
			
		||||
                target_interfaces_is="dhcp-raw"
 | 
			
		||||
            fi
 | 
			
		||||
        ;;
 | 
			
		||||
    esac
 | 
			
		||||
    echo "done."
 | 
			
		||||
    echo
 | 
			
		||||
 | 
			
		||||
    echo -n "Waiting for networking to become ready... "
 | 
			
		||||
    while ! ping -q -c 1 8.8.8.8 &>/dev/null; do
 | 
			
		||||
        sleep 1
 | 
			
		||||
    done
 | 
			
		||||
    echo "done."
 | 
			
		||||
    echo
 | 
			
		||||
 | 
			
		||||
    echo "4a) Please enter an alternate Debian release codename for the system if desired."
 | 
			
		||||
    echo "    Supported: ${supported_debrelease}"
 | 
			
		||||
    echo "    Default: ${default_debrelease}"
 | 
			
		||||
    while [[ -z ${debrelease} ]]; do
 | 
			
		||||
        echo
 | 
			
		||||
        echo -n "> "
 | 
			
		||||
        read debrelease
 | 
			
		||||
        if [[ -z ${debrelease} ]]; then
 | 
			
		||||
            debrelease="${default_debrelease}"
 | 
			
		||||
        fi
 | 
			
		||||
        if ! grep -qw "${debrelease}" <<<"${supported_debrelease}"; then
 | 
			
		||||
            debrelease=""
 | 
			
		||||
            echo
 | 
			
		||||
            echo "Please enter a valid release."
 | 
			
		||||
            continue
 | 
			
		||||
        fi
 | 
			
		||||
        echo
 | 
			
		||||
    done
 | 
			
		||||
 | 
			
		||||
    echo "4b) Please enter an HTTP URL for an alternate Debian mirror if desired."
 | 
			
		||||
    echo "    Default: ${default_debmirror}"
 | 
			
		||||
    while [[ -z ${debmirror} ]]; do
 | 
			
		||||
        echo
 | 
			
		||||
        echo -n "> "
 | 
			
		||||
        read debmirror
 | 
			
		||||
        if [[ -z ${debmirror} ]]; then
 | 
			
		||||
            debmirror="${default_debmirror}"
 | 
			
		||||
        fi
 | 
			
		||||
        if ! wget -O /dev/null ${debmirror}/dists/${debrelease}/Release &>/dev/null; then
 | 
			
		||||
            debmirror=""
 | 
			
		||||
            echo
 | 
			
		||||
            echo "Please enter a valid Debian mirror URL."
 | 
			
		||||
            continue
 | 
			
		||||
        fi
 | 
			
		||||
        echo
 | 
			
		||||
        echo "Repository mirror '${debmirror}' successfully validated."
 | 
			
		||||
        echo
 | 
			
		||||
    done
 | 
			
		||||
 | 
			
		||||
    target_keys_method="wget"
 | 
			
		||||
    echo "5) Please enter an HTTP URL containing a text list of SSH authorized keys to"
 | 
			
		||||
    echo "fetch. These keys will be allowed access to the deployment user 'XXDEPLOYUSER'"
 | 
			
		||||
    echo "via SSH."
 | 
			
		||||
    echo ""
 | 
			
		||||
    echo "Leave blank to bypass this and use a password instead."
 | 
			
		||||
    echo
 | 
			
		||||
    echo -n "> "
 | 
			
		||||
    read target_keys_path
 | 
			
		||||
    if [[ -z ${target_keys_path} ]]; then
 | 
			
		||||
        echo
 | 
			
		||||
        echo "No SSH keys URL specified. Falling back to password configuration."
 | 
			
		||||
        echo
 | 
			
		||||
        echo "5) Please enter a password (hidden), twice, for the deployment user '${target_deploy_user}'."
 | 
			
		||||
        while [[ -z "${target_password}" ]]; do
 | 
			
		||||
            echo
 | 
			
		||||
            echo -n "> "
 | 
			
		||||
            read -s target_password_1
 | 
			
		||||
            echo
 | 
			
		||||
            echo -n "> "
 | 
			
		||||
            read -s target_password_2
 | 
			
		||||
            echo
 | 
			
		||||
            if [[ -n "${target_password_1}" && "${target_password_1}" -eq "${target_password_2}" ]]; then
 | 
			
		||||
                target_password="${target_password_1}"
 | 
			
		||||
            else
 | 
			
		||||
                echo
 | 
			
		||||
                echo "The specified passwords do not match or are empty."
 | 
			
		||||
            fi
 | 
			
		||||
        done
 | 
			
		||||
    else
 | 
			
		||||
        while ! wget -O /dev/null ${target_keys_path} &>/dev/null; do
 | 
			
		||||
            echo
 | 
			
		||||
            echo "Please enter a valid SSH keys URL."
 | 
			
		||||
            echo
 | 
			
		||||
            echo -n "> "
 | 
			
		||||
            read target_keys_path
 | 
			
		||||
        done
 | 
			
		||||
        echo
 | 
			
		||||
        echo "SSH key source '${target_keys_path}' successfully validated."
 | 
			
		||||
    fi
 | 
			
		||||
    echo
 | 
			
		||||
}    
 | 
			
		||||
 | 
			
		||||
case ${install_option} in
 | 
			
		||||
    on)
 | 
			
		||||
        seed_config
 | 
			
		||||
    ;;
 | 
			
		||||
    *)
 | 
			
		||||
        interactive_config
 | 
			
		||||
    ;;
 | 
			
		||||
esac
 | 
			
		||||
 | 
			
		||||
titlestring_text="| Proceeding with installation of host '${target_hostname}'. |"
 | 
			
		||||
titlestring_len="$(( $( wc -c <<<"${titlestring_text}" ) - 2 ))"
 | 
			
		||||
for i in $( seq 0 ${titlestring_len} ); do echo -n "-"; done; echo
 | 
			
		||||
echo "${titlestring_text}"
 | 
			
		||||
for i in $( seq 0 ${titlestring_len} ); do echo -n "-"; done; echo
 | 
			
		||||
echo
 | 
			
		||||
 | 
			
		||||
### Script begins ###
 | 
			
		||||
echo "LOGFILE: ${logfile}"
 | 
			
		||||
echo
 | 
			
		||||
 | 
			
		||||
exec 1> >( tee -ia ${logfile} )
 | 
			
		||||
exec 2> >( tee -ia ${logfile} >/dev/null )
 | 
			
		||||
set -o errexit
 | 
			
		||||
set -o xtrace
 | 
			
		||||
 | 
			
		||||
case ${install_option} in
 | 
			
		||||
    on)
 | 
			
		||||
        seed_checkin start
 | 
			
		||||
    ;;
 | 
			
		||||
    *)
 | 
			
		||||
        # noop
 | 
			
		||||
        true
 | 
			
		||||
    ;;
 | 
			
		||||
esac
 | 
			
		||||
 | 
			
		||||
cleanup() {
 | 
			
		||||
    set +o errexit
 | 
			
		||||
    echo -n "Cleaning up... "
 | 
			
		||||
    umount ${target}/tmp >&2
 | 
			
		||||
    umount ${target}/run >&2
 | 
			
		||||
    umount ${target}/sys >&2
 | 
			
		||||
    umount ${target}/proc >&2
 | 
			
		||||
    umount ${target}/dev/pts >&2
 | 
			
		||||
    umount ${target}/dev >&2
 | 
			
		||||
    umount ${target}/var/lib/ceph >&2
 | 
			
		||||
    umount ${target}/var/lib/zookeeper >&2
 | 
			
		||||
    umount ${target}/boot/efi >&2
 | 
			
		||||
    umount ${target}/boot >&2
 | 
			
		||||
    umount ${target} >&2
 | 
			
		||||
    vgchange -an >&2
 | 
			
		||||
    rmdir ${target} >&2
 | 
			
		||||
    rm ${lockfile}
 | 
			
		||||
    echo "done."
 | 
			
		||||
    echo
 | 
			
		||||
 | 
			
		||||
    case ${install_option} in
 | 
			
		||||
        on)
 | 
			
		||||
            respawn
 | 
			
		||||
        ;;
 | 
			
		||||
        *)
 | 
			
		||||
            # noop
 | 
			
		||||
            true
 | 
			
		||||
        ;;
 | 
			
		||||
    esac
 | 
			
		||||
}
 | 
			
		||||
trap cleanup EXIT
 | 
			
		||||
 | 
			
		||||
echo -n "Determining partition sizes... "
 | 
			
		||||
blockdev_size_bytes="$( blockdev --getsize64 ${target_disk} )"
 | 
			
		||||
blockdev_size_gbytes="$(( ${blockdev_size_bytes} / 1024 / 1024 / 1024 - 1))"
 | 
			
		||||
if [[ ${blockdev_size_gbytes} -ge 100 ]]; then
 | 
			
		||||
    # Optimal sized system disk (>=100GB), use large partitions
 | 
			
		||||
    size_root_lv="32"
 | 
			
		||||
    size_ceph_lv="8"
 | 
			
		||||
    size_zookeeper_lv="32"
 | 
			
		||||
    size_swap_lv="16"
 | 
			
		||||
    echo "found large disk (${blockdev_size_gbytes} >= 100GB), using optimal partition sizes."
 | 
			
		||||
else
 | 
			
		||||
    # Minimum sized disk (>=30GB), use small partitions
 | 
			
		||||
    size_root_lv="8"
 | 
			
		||||
    size_ceph_lv="4"
 | 
			
		||||
    size_zookeeper_lv="8"
 | 
			
		||||
    size_swap_lv="8"
 | 
			
		||||
    echo "found small disk (${blockdev_size_gbytes} < 100GB), using small partition sizes."
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
echo -n "Disabing existing volume groups... "
 | 
			
		||||
vgchange -an >&2 || true
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
blockcheck() {
 | 
			
		||||
    # Use for testing only
 | 
			
		||||
    if [[ -n ${SKIP_BLOCKCHECK} ]]; then
 | 
			
		||||
        return
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    # Determine optimal block size for zeroing
 | 
			
		||||
    exponent=16
 | 
			
		||||
    remainder=1
 | 
			
		||||
    while [[ ${remainder} -gt 0 && ${exponent} -gt 0 ]]; do
 | 
			
		||||
        exponent=$(( ${exponent} - 1 ))
 | 
			
		||||
        size=$(( 2**9 * 2 ** ${exponent} ))
 | 
			
		||||
        count=$(( ${blockdev_size_bytes} / ${size} ))
 | 
			
		||||
        remainder=$(( ${blockdev_size_bytes} - ${count} * ${size} ))
 | 
			
		||||
    done
 | 
			
		||||
    if [[ ${remainder} -gt 0 ]]; then
 | 
			
		||||
        echo "Failed to find a suitable block size for wiping... skipping."
 | 
			
		||||
        return
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    echo -n "Checking if block device '${target_disk}' is already wiped... "
 | 
			
		||||
    if ! cmp --silent --bytes ${blockdev_size_bytes} /dev/zero ${target_disk}; then
 | 
			
		||||
        echo "false."
 | 
			
		||||
        echo "Wiping block device '${target_disk}' (${count} blocks of ${size} bytes)..."
 | 
			
		||||
        dd if=/dev/zero of=${target_disk} bs=${size} count=${count} oflag=direct status=progress 2>&1
 | 
			
		||||
    else
 | 
			
		||||
        echo "done."
 | 
			
		||||
    fi
 | 
			
		||||
}
 | 
			
		||||
blockcheck
 | 
			
		||||
 | 
			
		||||
echo -n "Preparing block device '${target_disk}'... "
 | 
			
		||||
# New GPT, part 1 64MB ESP, part 2 960MB BOOT, part 3 inf LVM PV
 | 
			
		||||
echo -e "o\ny\nn\n1\n\n64M\nEF00\nn\n2\n\n960M\n8300\nn\n3\n\n\n8E00\nw\ny\n" | gdisk ${target_disk} >&2
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
echo -n "Rescanning disks... "
 | 
			
		||||
partprobe >&2 || true
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
echo -n "Creating LVM PV... "
 | 
			
		||||
yes | pvcreate -ffy ${target_disk}3 >&2
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
echo -n "Creating LVM VG 'vgx'... "
 | 
			
		||||
yes | vgcreate vgx ${target_disk}3 >&2
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
echo -n "Creating root logical volume (${size_root_lv}GB)... "
 | 
			
		||||
yes | lvcreate -L ${size_root_lv}G -n root vgx >&2
 | 
			
		||||
echo "done."
 | 
			
		||||
echo -n "Creating filesystem on root logical volume (ext4)... "
 | 
			
		||||
yes | mkfs.ext4 /dev/vgx/root >&2
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
echo -n "Creating ceph logical volume (${size_ceph_lv}GB)... "
 | 
			
		||||
yes | lvcreate -L ${size_ceph_lv}G -n ceph vgx >&2
 | 
			
		||||
echo "done."
 | 
			
		||||
echo -n "Creating filesystem on ceph logical volume (ext4)... "
 | 
			
		||||
yes | mkfs.ext4 /dev/vgx/ceph >&2
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
echo -n "Creating zookeeper logical volume (${size_zookeeper_lv}GB)... "
 | 
			
		||||
yes | lvcreate -L ${size_zookeeper_lv}G -n zookeeper vgx >&2
 | 
			
		||||
echo "done."
 | 
			
		||||
echo -n "Creating filesystem on zookeeper logical volume (ext4)... "
 | 
			
		||||
yes | mkfs.ext4 /dev/vgx/zookeeper >&2
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
echo -n "Creating swap logical volume (${size_swap_lv}GB)... "
 | 
			
		||||
yes | lvcreate -L ${size_swap_lv}G -n swap vgx >&2
 | 
			
		||||
echo "done."
 | 
			
		||||
echo -n "Creating swap space on swap logical volume... "
 | 
			
		||||
yes | mkswap -f /dev/vgx/swap >&2
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
echo -n "Creating filesystem on boot partition (ext2)... "
 | 
			
		||||
yes | mkfs.ext2 ${target_disk}2 >&2
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
echo -n "Creating filesystem on ESP partition (vfat)... "
 | 
			
		||||
yes | mkdosfs -F32 ${target_disk}1 >&2
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
vgchange -ay >&2
 | 
			
		||||
target="/tmp/target"
 | 
			
		||||
mkdir -p ${target} >&2
 | 
			
		||||
echo -n "Mounting disks on temporary target '${target}'... "
 | 
			
		||||
mount /dev/vgx/root ${target} >&2
 | 
			
		||||
mkdir -p ${target}/boot >&2
 | 
			
		||||
chattr +i ${target}/boot >&2
 | 
			
		||||
mount ${target_disk}2 ${target}/boot >&2
 | 
			
		||||
mkdir -p ${target}/boot/efi >&2
 | 
			
		||||
chattr +i ${target}/boot/efi >&2
 | 
			
		||||
mount ${target_disk}1 ${target}/boot/efi >&2
 | 
			
		||||
mkdir -p ${target}/var/lib/ceph >&2
 | 
			
		||||
chattr +i ${target}/var/lib/ceph >&2
 | 
			
		||||
mount /dev/vgx/ceph ${target}/var/lib/ceph >&2
 | 
			
		||||
mkdir -p ${target}/var/lib/zookeeper >&2
 | 
			
		||||
chattr +i ${target}/var/lib/zookeeper >&2
 | 
			
		||||
mount /dev/vgx/zookeeper ${target}/var/lib/zookeeper >&2
 | 
			
		||||
mkdir -p ${target}/tmp >&2
 | 
			
		||||
chattr +i ${target}/tmp >&2
 | 
			
		||||
mount -t tmpfs tmpfs ${target}/tmp >&2
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
echo -n "Running debootstrap install... "
 | 
			
		||||
echo "Command: debootstrap --include=${inclpkglist} ${debrelease} ${target}/ ${debmirror}" >&2
 | 
			
		||||
debootstrap --include=${inclpkglist} ${debrelease} ${target}/ ${debmirror} >&2
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
echo -n "Adding non-free repository (firmware, etc.)... "
 | 
			
		||||
mkdir -p ${target}/etc/apt/sources.list.d/ >&2
 | 
			
		||||
echo "deb ${debmirror} ${debrelease} contrib non-free" | tee -a ${target}/etc/apt/sources.list >&2
 | 
			
		||||
chroot ${target} apt update >&2
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
echo -n "Installing supplemental packages... "
 | 
			
		||||
chroot ${target} apt install -y --no-install-recommends $( sed 's/,/ /g' <<<"${suppkglist}" ) >&2
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
# Determine the bypath name of the specified system disk
 | 
			
		||||
for disk in /dev/disk/by-path/*; do
 | 
			
		||||
    bypathlink="$( realpath ${disk} | awk -F'/' '{ print $NF }' )"
 | 
			
		||||
    enteredname="$( awk -F'/' '{ print $NF }' <<<"${target_disk}" )"
 | 
			
		||||
    if [[ ${bypathlink} == ${enteredname} ]]; then
 | 
			
		||||
        bypath_disk="${disk}"
 | 
			
		||||
    fi
 | 
			
		||||
done
 | 
			
		||||
 | 
			
		||||
echo -n "Adding fstab entries... "
 | 
			
		||||
echo "/dev/mapper/vgx-root / ext4 errors=remount-ro 0 1" | tee -a ${target}/etc/fstab >&2
 | 
			
		||||
echo "/dev/mapper/vgx-ceph /var/lib/ceph ext4 errors=remount-ro 0 2" | tee -a ${target}/etc/fstab >&2
 | 
			
		||||
echo "/dev/mapper/vgx-zookeeper /var/lib/zookeeper ext4 errors=remount-ro 0 2" | tee -a ${target}/etc/fstab >&2
 | 
			
		||||
echo "/dev/mapper/vgx-swap none swap sw 0 0" | tee -a ${target}/etc/fstab >&2
 | 
			
		||||
echo "${bypath_disk}-part2 /boot ext2 defaults 0 2" | tee -a ${target}/etc/fstab >&2
 | 
			
		||||
echo "${bypath_disk}-part1 /boot/efi vfat umask=0077 0 2" | tee -a ${target}/etc/fstab >&2
 | 
			
		||||
echo "tmpfs /tmp tmpfs defaults 0 0" | tee -a ${target}/etc/fstab >&2
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
seed_interfaces_segment() {
 | 
			
		||||
    # A seed install is always "dhcp-raw" since the provisioner is always a dedicated, access port
 | 
			
		||||
    target_interfaces_block="auto ${target_interface}\niface ${target_interface} inet dhcp\npost-up /etc/network/pvcprovisionerd.checkin.sh \$IFACE"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interactive_interfaces_segment() {
 | 
			
		||||
    case ${target_interfaces_is} in
 | 
			
		||||
        static-vlan)
 | 
			
		||||
            target_interfaces_block="auto ${vlan_interface}\niface ${vlan_interface} inet ${target_netformat}\n\tvlan_raw_device ${target_interface}\n\taddress ${formatted_ipaddr}\n\tnetmask ${formatted_netmask}\n\tgateway ${target_defgw}"
 | 
			
		||||
        ;;
 | 
			
		||||
        static-raw)
 | 
			
		||||
            target_interfaces_block="auto ${target_interface}\niface ${target_interface} inet ${target_netformat}\n\taddress ${formatted_ipaddr}\n\tnetmask ${formatted_netmask}\n\tgateway ${target_defgw}"
 | 
			
		||||
        ;;
 | 
			
		||||
        dhcp-vlan)
 | 
			
		||||
            target_interfaces_block="auto ${vlan_interface}\niface ${vlan_interface} inet ${target_netformat}\n\tvlan_raw_device${target_interface}"
 | 
			
		||||
        ;;
 | 
			
		||||
        dhcp-raw)
 | 
			
		||||
            target_interfaces_block="auto ${target_interface}\niface ${target_interface} inet ${target_netformat}"
 | 
			
		||||
        ;;
 | 
			
		||||
    esac
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
echo -n "Creating bootstrap interface segment... "
 | 
			
		||||
case ${install_option} in
 | 
			
		||||
    on)
 | 
			
		||||
        seed_interfaces_segment
 | 
			
		||||
    ;;
 | 
			
		||||
    *)
 | 
			
		||||
        interactive_interfaces_segment
 | 
			
		||||
    ;;
 | 
			
		||||
esac
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
echo -n "Adding bootstrap interface segment... "
 | 
			
		||||
echo -e "${target_interfaces_block}" | tee ${target}/etc/network/interfaces.d/${target_interface} >&2
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
case ${install_option} in
 | 
			
		||||
    on)
 | 
			
		||||
        echo -n "Creating bond interface segment... "
 | 
			
		||||
        bond_interfaces="$( ip -br link show | grep -E -o '^e[a-z]+[0-9]+[a-z0-9]*' | grep -v "^${target_interface}$" | tr '\n' ' ' )"
 | 
			
		||||
        bond_interfaces_block="auto bond0\niface bond0 inet manual\n\tbond-mode 802.3ad\n\tbond-slaves ${bond_interfaces}\n\tpost-up ip link set mtu 9000 dev \$IFACE"
 | 
			
		||||
        echo "done."
 | 
			
		||||
 | 
			
		||||
        echo -n "Adding bond interface segment... "
 | 
			
		||||
        echo -e "${bond_interfaces_block}" | tee ${target}/etc/network/interfaces.d/bond0 >&2
 | 
			
		||||
        echo "done."
 | 
			
		||||
 | 
			
		||||
        echo -n "Adding bootstrap interface post-up checkin script... "
 | 
			
		||||
        cat <<EOF | tee ${target}/etc/network/pvcprovisionerd.checkin.sh >&2
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
target_interface=\${1}
 | 
			
		||||
pvcbootstrapd_checkin_uri="${pvcbootstrapd_checkin_uri}"
 | 
			
		||||
macaddr=\$( ip -br link show \${target_interface} | awk '{ print \$3 }' )
 | 
			
		||||
ipaddr=\$( ip -br address show \${target_interface} | awk '{ print \$3 }' | awk -F '/' '{ print \$1 }' )
 | 
			
		||||
bmc_macaddr=\$( ipmitool lan print | grep 'MAC Address  ' | awk '{ print $NF }' )
 | 
			
		||||
bmc_ipaddr=\$( ipmitool lan print | grep 'IP Address  ' | awk '{ print $NF }' )
 | 
			
		||||
if [[ -f /etc/pvc-install.pvcbootstrapd_completed ]]; then
 | 
			
		||||
    # The third boot, when all pvcprovisionerd plugins have been run (this script will henceforth do nothing)
 | 
			
		||||
    action="system-boot_bootstrap-completed"
 | 
			
		||||
elif [[ -f /etc/pvc-install.base && -f /etc/pvc-install.pvc ]]; then
 | 
			
		||||
    # The second boot, when Ansible has been run and plugins running
 | 
			
		||||
    action="system-boot_ansible-completed"
 | 
			
		||||
    touch /etc/pvc-install.pvcbootstrapd_completed
 | 
			
		||||
else
 | 
			
		||||
    # The first boot, when Ansible has not been run yet
 | 
			
		||||
    action="system-boot_initial"
 | 
			
		||||
fi
 | 
			
		||||
curl -X POST \
 | 
			
		||||
    -H "Content-Type: application/json" \
 | 
			
		||||
    -d "{\"action\":\"\${action}\",\"macaddr\":\"\${macaddr}\",\"ipaddr\":\"\${ipaddr}\",\"hostname\":\"\$( hostname -s )\",\"bmc_macaddr\":\"\${bmc_macaddr}\",\"bmc_ipaddr\":\"\${bmc_ipaddr}\"}" \
 | 
			
		||||
    \${pvcbootstrapd_checkin_uri}
 | 
			
		||||
 | 
			
		||||
if [[ -f /etc/pvc-install.pvcbootstrapd_completed ]]; then
 | 
			
		||||
    # Clean up the bootstrap interface and this script
 | 
			
		||||
    rm /etc/network/interfaces.d/\${target_interface}
 | 
			
		||||
    rm \$0
 | 
			
		||||
    exit 0
 | 
			
		||||
fi
 | 
			
		||||
EOF
 | 
			
		||||
        chmod +x ${target}/etc/network/pvcprovisionerd.checkin.sh
 | 
			
		||||
        echo "done."
 | 
			
		||||
    ;;
 | 
			
		||||
    *)
 | 
			
		||||
        # noop
 | 
			
		||||
        true
 | 
			
		||||
    ;;
 | 
			
		||||
esac
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
echo -n "Setting temporary 'root' password... "
 | 
			
		||||
echo "root:${root_password}" | chroot ${target} chpasswd >&2
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
echo -n "Adding deployment user... "
 | 
			
		||||
mv ${target}/home ${target}/var/home >&2
 | 
			
		||||
chroot ${target} useradd -u 200 -d /var/home/${target_deploy_user} -m -s /bin/bash -g operator -G sudo ${target_deploy_user} >&2
 | 
			
		||||
chroot ${target} mkdir -p /var/home/${target_deploy_user}/.ssh
 | 
			
		||||
if [[ -n ${target_keys_path} ]]; then
 | 
			
		||||
    case ${target_keys_method} in
 | 
			
		||||
        wget)
 | 
			
		||||
            wget -O ${target}/var/home/${target_deploy_user}/.ssh/authorized_keys ${target_keys_path}
 | 
			
		||||
        ;;
 | 
			
		||||
        tftp)
 | 
			
		||||
            tftp -m binary "${seed_host}" -c get "${target_keys_path}" ${target}/var/home/${target_deploy_user}/.ssh/authorized_keys
 | 
			
		||||
        ;;
 | 
			
		||||
    esac
 | 
			
		||||
    chroot ${target} chmod 0600 /var/home/${target_deploy_user}/.ssh/authorized_keys
 | 
			
		||||
    chroot ${target} chown -R ${target_deploy_user}:operator /var/home/${target_deploy_user}
 | 
			
		||||
else
 | 
			
		||||
    echo "${target_deploy_user}:${target_password}" | chroot ${target} chpasswd >&2
 | 
			
		||||
fi
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
echo -n "Setting NOPASSWD for sudo group... "
 | 
			
		||||
sed -i 's/^%sudo\tALL=(ALL:ALL) ALL/%sudo\tALL=(ALL:ALL) NOPASSWD: ALL/' ${target}/etc/sudoers
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
echo -n "Setting /etc/issue generator... "
 | 
			
		||||
mkdir -p ${target}/etc/network/if-up.d >&2
 | 
			
		||||
echo -e "#!/bin/sh
 | 
			
		||||
IP=\"\$( ip -4 addr show dev ${target_interface} | grep inet | awk '{ print \$2 }' | head -1 )\"
 | 
			
		||||
cat <<EOF >/etc/issue
 | 
			
		||||
Debian GNU/Linux 10 \\\\n \\\\l
 | 
			
		||||
 | 
			
		||||
Bootstrap interface IP address: \$IP
 | 
			
		||||
 | 
			
		||||
EOF" | tee ${target}/etc/network/if-up.d/issue-gen >&2
 | 
			
		||||
chmod +x ${target}/etc/network/if-up.d/issue-gen 1>&2
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
echo -n "Generating host rsa and ed25519 keys... "
 | 
			
		||||
rm ${target}/etc/ssh/ssh_host_*_key* >&2
 | 
			
		||||
chroot ${target} ssh-keygen -t rsa -N "" -f /etc/ssh/ssh_host_rsa_key >&2
 | 
			
		||||
chroot ${target} ssh-keygen -t ed25519 -N "" -f /etc/ssh/ssh_host_ed25519_key >&2
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
echo -n "Setting hostname... "
 | 
			
		||||
echo "${target_hostname}" | tee ${target}/etc/hostname >&2
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
echo -n "Setting resolv.conf... "
 | 
			
		||||
echo "nameserver 8.8.8.8" | tee ${target}/etc/resolv.conf >&2
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
echo -n "Installing GRUB bootloader... "
 | 
			
		||||
mount --bind /dev ${target}/dev >&2
 | 
			
		||||
mount --bind /dev/pts ${target}/dev/pts >&2
 | 
			
		||||
mount --bind /proc ${target}/proc >&2
 | 
			
		||||
mount --bind /sys ${target}/sys >&2
 | 
			
		||||
mount --bind /run ${target}/run >&2
 | 
			
		||||
if [[ -d /sys/firmware/efi ]]; then
 | 
			
		||||
    bios_target="x86_64-efi"
 | 
			
		||||
else
 | 
			
		||||
    bios_target="i386-pc"
 | 
			
		||||
fi
 | 
			
		||||
cat <<EOF | tee ${target}/etc/default/grub >&2
 | 
			
		||||
GRUB_DEFAULT=0
 | 
			
		||||
GRUB_TIMEOUT=5
 | 
			
		||||
GRUB_DISTRIBUTOR="Parallel Virtual Cluster (PVC) - Debian"
 | 
			
		||||
GRUB_CMDLINE_LINUX="console=hvc0 console=tty0 console=ttyS0,115200"
 | 
			
		||||
GRUB_TERMINAL_INPUT="console serial"
 | 
			
		||||
GRUB_TERMINAL_OUTPUT="gfxterm serial"
 | 
			
		||||
GRUB_SERIAL_COMMAND="serial --unit=0 --unit=1 --speed=115200"
 | 
			
		||||
EOF
 | 
			
		||||
chroot ${target} grub-install --force --target=${bios_target} ${target_disk} >&2
 | 
			
		||||
chroot ${target} grub-mkconfig -o /boot/grub/grub.cfg >&2
 | 
			
		||||
echo "done."
 | 
			
		||||
 | 
			
		||||
seed_postinst() {
 | 
			
		||||
    cleanup
 | 
			
		||||
    echo "Temporary root password: ${root_password}"
 | 
			
		||||
    seed_checkin end
 | 
			
		||||
 | 
			
		||||
    echo -n "Rebooting in 10 seconds..."
 | 
			
		||||
    i=10
 | 
			
		||||
    while [[ ${i} -gt 0 ]]; do
 | 
			
		||||
        sleep 1
 | 
			
		||||
        i=$(( ${1} - 1 ))
 | 
			
		||||
        echo -n "."
 | 
			
		||||
    done
 | 
			
		||||
    echo
 | 
			
		||||
    reboot
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interactive_postinst() {
 | 
			
		||||
    set +o errexit
 | 
			
		||||
    echo
 | 
			
		||||
    echo -n "Edit the /etc/network/interfaces file in the target before completing setup? If you plan to use bonding, it is prudent to set this up in basic form now! [y/N] "
 | 
			
		||||
    read edit_ifaces
 | 
			
		||||
    if [[ ${edit_ifaces} == 'y' || ${edit_ifaces} == 'Y' ]]; then
 | 
			
		||||
        vim ${target}/etc/network/interfaces
 | 
			
		||||
    fi
 | 
			
		||||
    echo
 | 
			
		||||
 | 
			
		||||
    echo -n "Launch a chroot shell in the target environment? [y/N] "
 | 
			
		||||
    read launch_chroot
 | 
			
		||||
    if [[ ${launch_chroot} == 'y' || ${edit_ifaces} == 'Y' ]]; then
 | 
			
		||||
        echo "Type 'exit' or Ctrl+D to exit chroot."
 | 
			
		||||
        chroot ${target} /bin/bash
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    cleanup
 | 
			
		||||
 | 
			
		||||
    echo "-------------------------------------------------------------------------------------"
 | 
			
		||||
    echo "| PVC node installation finished. Next steps:                                       |"
 | 
			
		||||
    echo "| 1. Press <enter> to reboot the system.                                            |"
 | 
			
		||||
    echo "| 2. Boot the system verify SSH access (IP shown on login screen).                  |"
 | 
			
		||||
    echo "| 3. Proceed with system deployment via PVC Ansible.                                |"
 | 
			
		||||
    echo "|                                                                                   |"
 | 
			
		||||
    echo "| The INSECURE temporary root password if the system will not boot is: ${root_password}     |"
 | 
			
		||||
    echo "-------------------------------------------------------------------------------------"
 | 
			
		||||
    echo
 | 
			
		||||
    read
 | 
			
		||||
 | 
			
		||||
    reboot
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
case ${install_option} in
 | 
			
		||||
    on)
 | 
			
		||||
        seed_postinst
 | 
			
		||||
    ;;
 | 
			
		||||
    *)
 | 
			
		||||
        interactive_postinst
 | 
			
		||||
    ;;
 | 
			
		||||
esac
 | 
			
		||||
							
								
								
									
										1
									
								
								templates/installer.list.chroot
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								templates/installer.list.chroot
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
live-task-standard live-tools live-boot live-boot-initramfs-tools linux-image-amd64 psmisc mdadm lvm2 parted gdisk dosfstools debootstrap grub-pc-bin grub-efi-amd64 sipcalc vim ca-certificates vlan tftp-hpa curl ipmitool
 | 
			
		||||
							
								
								
									
										2
									
								
								templates/logind.conf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								templates/logind.conf
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,2 @@
 | 
			
		||||
[Login]
 | 
			
		||||
NAutoVTs=2
 | 
			
		||||
							
								
								
									
										1
									
								
								templates/resolv.conf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								templates/resolv.conf
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
nameserver 8.8.8.8
 | 
			
		||||
							
								
								
									
										1
									
								
								templates/root.bashrc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								templates/root.bashrc
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
/install.sh
 | 
			
		||||
							
								
								
									
										3
									
								
								templates/serial-getty-override.conf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								templates/serial-getty-override.conf
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
			
		||||
[Service]
 | 
			
		||||
ExecStart=
 | 
			
		||||
ExecStart=-/sbin/agetty -o '-p -- \\u' --autologin root --noclear --keep-baud 115200,38400,9600 %I $TERM
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 33 KiB  | 
		Reference in New Issue
	
	Block a user