Compare commits

..

10 Commits

Author SHA1 Message Date
Joshua Boniface 133d6fe994 Complete implementation of seed install
Some fixed decisions were made, namely that bond0 would be created by
the installer from "all other interfaces" to facilitate easy
provisioning.
2021-12-11 18:48:26 -05:00
Joshua Boniface c1be2d316b Add collision detection 2021-12-06 23:50:08 -05:00
Joshua Boniface 2b60ea27dd Fix package lists for bullseye 2021-12-06 23:12:13 -05:00
Joshua Boniface 318449d55b Improve log messages 2021-12-06 15:06:43 -05:00
Joshua Boniface 56d0f90baf Fix bad variable name 2021-12-06 14:56:32 -05:00
Joshua Boniface 152e176bd6 Add dosfstools to package list 2021-12-06 13:54:02 -05:00
Joshua Boniface 2927f9f6ca Optimize install.sh
1. Fix borked logfile
2. Exclude systemd-timesyncd for bullseye installs
3. Optimize block zeroing
4. Add some missing yes| in lvcreate/mkfs
2021-12-06 13:52:35 -05:00
Joshua Boniface 24758a765b Improve preseeding config 2021-12-06 02:49:33 -05:00
Joshua Boniface cafcfca9d0 Finish up seed install 2021-12-06 01:13:11 -05:00
Joshua Boniface f8e2eb7395 Work on modular installer 2021-12-06 01:12:44 -05:00
5 changed files with 664 additions and 327 deletions

View File

@ -63,7 +63,7 @@ while [ $# -gt 0 ]; do
esac esac
done done
PACKAGE_LIST_MAIN="live-tools linux-image-amd64 mdadm lvm2 parted gdisk debootstrap grub-pc-bin grub-efi-amd64 sipcalc vim ca-certificates vlan" 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" PACKAGE_LIST_NONFREE="firmware-bnx2 firmware-bnx2x"
mkdir -p artifacts/lb mkdir -p artifacts/lb

View File

@ -114,10 +114,6 @@ build_pxe() {
# Set global variables # Set global variables
set root-url tftp://\${next-server} set root-url tftp://\${next-server}
set host-url tftp://\${next-server}/host
# Load host/mac-*.ipxe if present (per-host host-args configuration)
chain --autofree \${host-url}/mac-\${mac:hexraw}.ipxe ||
set menu-default pvc-installer set menu-default pvc-installer
set submenu-default pvc-installer set submenu-default pvc-installer
@ -125,11 +121,24 @@ set submenu-default pvc-installer
:pvc-installer :pvc-installer
kernel \${root-url}/vmlinuz kernel \${root-url}/vmlinuz
initrd \${root-url}/initrd.img initrd \${root-url}/initrd.img
imgargs vmlinuz console=tty0 console=ttyS0,115200n8 boot=live components timezone=America/Toronto fetch=\${root-url}/filesystem.squashfs username=root \${host-args} imgargs vmlinuz console=tty0 console=ttyS0,115200n8 vga=normal nomodeset boot=live components ethdevice-timeout=60 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 boot
EOF EOF
echo "done." 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."
popd &>/dev/null
echo "done."
echo -n "Downloading iPXE binary undionly.kpxe (chainloads UEFI clients)... "
pushd ${outputdir} &>/dev/null
wget -O ipxe.efi https://boot.ipxe.org/ipxe.efi &>/dev/null || fail "failed to download ipxe.efi."
popd &>/dev/null
echo "done."
sudo chown -R $(whoami) ${outputdir} sudo chown -R $(whoami) ${outputdir}
sudo chmod -R u+w ${outputdir} sudo chmod -R u+w ${outputdir}

35
install.seed.example Normal file
View File

@ -0,0 +1,35 @@
###
### General definitions
###
# The Debian release to use
debrelease="bullseye"
# The Debian mirror to use
debmirror="http://debian.mirror.rafal.ca/debian"
# Package list (installed during debootstrap)
debpkglist="lvm2,parted,gdisk,grub-pc,grub-efi-amd64,linux-image-amd64,sudo,vim,gpg,gpg-agent,aptitude,openssh-server,vlan,ifenslave,python2,python3,ca-certificates,ntp"
# Package list (installed in chroot)
suppkglist="firmware-linux,firmware-linux-nonfree,firmware-bnx2,firmware-bnx2x"
###
### Per-host definitions
###
# The hostname of the system (set per-run)
target_hostname="HOSTNAME"
# The target disk (either path or model to find; path overrides model if set)
target_disk_path="/dev/disk/by-path/pci-0000:01:00.0-scsi-0:2:0:0" # Example: Dell BOSS on R6515 via explicit path
target_disk_model="DELLBOSS VD" # Example: Dell BOSS on R6515 via model name
# SSH key method (usually tftp)
target_keys_method="tftp"
# SSH key path
target_keys_path="keys.txt"
# Deploy username
target_deploy_user="deploy"

View File

@ -1,17 +1,35 @@
#!/usr/bin/env bash #!/usr/bin/env bash
logfile="/tmp/pvc-install.log"
lockfile="/run/pvc-install.lock"
if [[ $( whoami ) != "root" ]]; then if [[ $( whoami ) != "root" ]]; then
echo "STOP! This script is designed to run as root within the installer only!" 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!" echo "Do not run it on your system. To build a PVC installer ISO, use './buildiso.sh' instead!"
exit 1 exit 1
fi fi
logfile="/tmp/pvc-install.log" # 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" supported_debrelease="buster bullseye"
default_debrelease="buster" default_debrelease="buster"
default_debmirror="http://debian.mirror.rafal.ca/debian" default_debmirror="http://debian.mirror.rafal.ca/debian"
debpkglist="lvm2,parted,gdisk,grub-pc,grub-efi-amd64,linux-image-amd64,sudo,vim,gpg,gpg-agent,aptitude,openssh-server,vlan,ifenslave,python2,python3,ca-certificates,ntp"
suppkglist="firmware-linux,firmware-linux-nonfree,firmware-bnx2,firmware-bnx2x" 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 # DANGER - THIS PASSWORD IS PUBLIC
# It should be used ONLY immediately after booting the PVC node in a SECURE environment # It should be used ONLY immediately after booting the PVC node in a SECURE environment
@ -20,10 +38,92 @@ suppkglist="firmware-linux,firmware-linux-nonfree,firmware-bnx2,firmware-bnx2x"
# roles will overwrite it by default during configuration. # roles will overwrite it by default during configuration.
root_password="hCb1y2PF" 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 clear
echo "--------------------------------------------------------" echo "--------------------------------------------------------"
echo "| PVC Node installer (XXDATEXX) |" echo "| PVC Node installer (${iso_name}) |"
echo "--------------------------------------------------------" echo "--------------------------------------------------------"
echo echo
echo "This LiveCD will install a PVC node base system ready for bootstrapping with 'pvc-ansible'." echo "This LiveCD will install a PVC node base system ready for bootstrapping with 'pvc-ansible'."
@ -80,8 +180,8 @@ while [[ ! -b ${target_disk} ]]; do
echo "Please enter a valid target disk." echo "Please enter a valid target disk."
continue continue
fi fi
blockdev_size="$(( $( blockdev --getsize64 ${target_disk} ) / 1024 / 1024 / 1024 - 1))" blockdev_size_gbytes="$(( $( blockdev --getsize64 ${target_disk} ) / 1024 / 1024 / 1024 - 1))"
if [[ ${blockdev_size} -lt 30 ]]; then if [[ ${blockdev_size_gbytes} -lt 30 ]]; then
target_disk="" target_disk=""
echo echo
echo "The specified disk is too small (<30 GB) to use as a PVC system disk." echo "The specified disk is too small (<30 GB) to use as a PVC system disk."
@ -183,16 +283,16 @@ case ${target_netformat} in
ip route add default via ${target_defgw} >&2 || true ip route add default via ${target_defgw} >&2 || true
formatted_ipaddr="$( sipcalc ${target_ipaddr} | grep -v '(' | awk '/Host address/{ print $NF }' )" formatted_ipaddr="$( sipcalc ${target_ipaddr} | grep -v '(' | awk '/Host address/{ print $NF }' )"
formatted_netmask="$( sipcalc ${target_ipaddr} | grep -v '(' | awk '/Network mask/{ print $NF }' )" formatted_netmask="$( sipcalc ${target_ipaddr} | grep -v '(' | awk '/Network mask/{ print $NF }' )"
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}"
real_interface="${vlan_interface}" real_interface="${vlan_interface}"
target_interfaces_is="static-vlan"
else else
ip link set ${target_interface} up >&2 || true ip link set ${target_interface} up >&2 || true
ip address add ${target_ipaddr} dev ${target_interface} >&2 || true ip address add ${target_ipaddr} dev ${target_interface} >&2 || true
ip route add default via ${target_defgw} >&2 || true ip route add default via ${target_defgw} >&2 || true
formatted_ipaddr="$( sipcalc ${target_ipaddr} | grep -v '(' | awk '/Host address/{ print $NF }' )" formatted_ipaddr="$( sipcalc ${target_ipaddr} | grep -v '(' | awk '/Host address/{ print $NF }' )"
formatted_netmask="$( sipcalc ${target_ipaddr} | grep -v '(' | awk '/Network mask/{ print $NF }' )" formatted_netmask="$( sipcalc ${target_ipaddr} | grep -v '(' | awk '/Network mask/{ print $NF }' )"
target_interfaces_block="auto ${target_interface}\niface ${target_interface} inet ${target_netformat}\n\taddress ${formatted_ipaddr}\n\tnetmask ${formatted_netmask}\n\tgateway ${target_defgw}"
real_interface="${target_interface}" real_interface="${target_interface}"
target_interfaces_is="static-raw"
fi fi
cat <<EOF >/etc/resolv.conf cat <<EOF >/etc/resolv.conf
nameserver 8.8.8.8 nameserver 8.8.8.8
@ -203,13 +303,13 @@ EOF
modprobe 8021q >&2 modprobe 8021q >&2
vconfig add ${target_interface} ${vlan_id} &>/dev/null vconfig add ${target_interface} ${vlan_id} &>/dev/null
vlan_interface=${target_interface}.${vlan_id} vlan_interface=${target_interface}.${vlan_id}
target_interfaces_block="auto ${vlan_interface}\niface ${vlan_interface} inet ${target_netformat}\n\tvlan_raw_device${target_interface}"
dhclient ${vlan_interface} >&2 dhclient ${vlan_interface} >&2
real_interface="${vlan_interface}" real_interface="${vlan_interface}"
target_interfaces_is="dhcp-vlan"
else else
target_interfaces_block="auto ${target_interface}\niface ${target_interface} inet ${target_netformat}"
dhclient ${target_interface} >&2 dhclient ${target_interface} >&2
real_interface="${target_interface}" real_interface="${target_interface}"
target_interfaces_is="dhcp-raw"
fi fi
;; ;;
esac esac
@ -262,6 +362,7 @@ while [[ -z ${debmirror} ]]; do
echo echo
done done
target_keys_method="wget"
echo "5) Please enter an HTTP URL containing a text list of SSH authorized keys to" 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 "fetch. These keys will be allowed access to the deployment user 'XXDEPLOYUSER'"
echo "via SSH." echo "via SSH."
@ -269,12 +370,12 @@ echo ""
echo "Leave blank to bypass this and use a password instead." echo "Leave blank to bypass this and use a password instead."
echo echo
echo -n "> " echo -n "> "
read target_keys_url read target_keys_path
if [[ -z ${target_keys_url} ]]; then if [[ -z ${target_keys_path} ]]; then
echo echo
echo "No SSH keys URL specified. Falling back to password configuration." echo "No SSH keys URL specified. Falling back to password configuration."
echo echo
echo "5) Please enter a password (hidden), twice, for the deployment user 'XXDEPLOYUSERXX'." echo "5) Please enter a password (hidden), twice, for the deployment user '${target_deploy_user}'."
while [[ -z "${target_password}" ]]; do while [[ -z "${target_password}" ]]; do
echo echo
echo -n "> " echo -n "> "
@ -291,17 +392,27 @@ if [[ -z ${target_keys_url} ]]; then
fi fi
done done
else else
while ! wget -O /dev/null ${target_keys_url} &>/dev/null; do while ! wget -O /dev/null ${target_keys_path} &>/dev/null; do
echo echo
echo "Please enter a valid SSH keys URL." echo "Please enter a valid SSH keys URL."
echo echo
echo -n "> " echo -n "> "
read target_keys_url read target_keys_path
done done
echo echo
echo "SSH key source '${target_keys_url}' successfully validated." echo "SSH key source '${target_keys_path}' successfully validated."
fi fi
echo echo
}
case ${install_option} in
on)
seed_config
;;
*)
interactive_config
;;
esac
titlestring_text="| Proceeding with installation of host '${target_hostname}'. |" titlestring_text="| Proceeding with installation of host '${target_hostname}'. |"
titlestring_len="$(( $( wc -c <<<"${titlestring_text}" ) - 2 ))" titlestring_len="$(( $( wc -c <<<"${titlestring_text}" ) - 2 ))"
@ -314,13 +425,25 @@ echo
echo "LOGFILE: ${logfile}" echo "LOGFILE: ${logfile}"
echo echo
set -o errexit
exec 1> >( tee -ia ${logfile} ) exec 1> >( tee -ia ${logfile} )
exec 2> >( tee -ia ${logfile} >/dev/null ) 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() { cleanup() {
set +o errexit set +o errexit
echo -n "Cleaning up... " echo -n "Cleaning up... "
umount ${target}/tmp >&2
umount ${target}/run >&2 umount ${target}/run >&2
umount ${target}/sys >&2 umount ${target}/sys >&2
umount ${target}/proc >&2 umount ${target}/proc >&2
@ -333,36 +456,74 @@ cleanup() {
umount ${target} >&2 umount ${target} >&2
vgchange -an >&2 vgchange -an >&2
rmdir ${target} >&2 rmdir ${target} >&2
rm ${lockfile}
echo "done." echo "done."
echo echo
case ${install_option} in
on)
respawn
;;
*)
# noop
true
;;
esac
} }
trap cleanup EXIT trap cleanup EXIT
echo -n "Determining block device and partition sizing... " echo -n "Determining partition sizes... "
blockdev_size="$(( $( blockdev --getsize64 ${target_disk} ) / 1024 / 1024 / 1024 - 1))" blockdev_size_bytes="$( blockdev --getsize64 ${target_disk} )"
if [[ ${blockdev_size} -ge 100 ]]; then 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 # Optimal sized system disk (>=100GB), use large partitions
size_root_lv="32" size_root_lv="32"
size_ceph_lv="8" size_ceph_lv="8"
size_zookeeper_lv="32" size_zookeeper_lv="32"
size_swap_lv="16" size_swap_lv="16"
echo "found large disk (>=100GB), using optimal partition sizes." echo "found large disk (${blockdev_size_gbytes} >= 100GB), using optimal partition sizes."
elif [[ ${blockdev_size} -ge 30 ]]; then else
# Minimum sized disk (>=30GB), use small partitions # Minimum sized disk (>=30GB), use small partitions
size_root_lv="8" size_root_lv="8"
size_ceph_lv="4" size_ceph_lv="4"
size_zookeeper_lv="8" size_zookeeper_lv="8"
size_swap_lv="8" size_swap_lv="8"
echo "found small disk (>=30GB), using small partition sizes." echo "found small disk (${blockdev_size_gbytes} < 100GB), using small partition sizes."
fi fi
echo -n "Disabing existing volume groups... " echo -n "Disabing existing volume groups... "
vgchange -an >&2 || true vgchange -an >&2 || true
echo "done." echo "done."
echo -n "Zeroing block device '${target_disk}'... " blockcheck() {
dd if=/dev/zero of=${target_disk} bs=4M >&2 || true # 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 -n "Wiping block device '${target_disk}' (${count} blocks of ${size} bytes)... "
dd if=/dev/zero of=${target_disk} bs=${size} count=${count} oflag=direct &>/dev/null
fi
echo "done." echo "done."
}
blockcheck
echo -n "Preparing block device '${target_disk}'... " echo -n "Preparing block device '${target_disk}'... "
# New GPT, part 1 64MB ESP, part 2 960MB BOOT, part 3 inf LVM PV # New GPT, part 1 64MB ESP, part 2 960MB BOOT, part 3 inf LVM PV
@ -377,12 +538,12 @@ echo -n "Creating LVM PV... "
yes | pvcreate -ffy ${target_disk}3 >&2 yes | pvcreate -ffy ${target_disk}3 >&2
echo "done." echo "done."
echo -n "Creating LVM VG named 'vgx'... " echo -n "Creating LVM VG 'vgx'... "
yes | vgcreate vgx ${target_disk}3 >&2 yes | vgcreate vgx ${target_disk}3 >&2
echo "done." echo "done."
echo -n "Creating root logical volume (${size_root_lv}GB)... " echo -n "Creating root logical volume (${size_root_lv}GB)... "
lvcreate -L ${size_root_lv}G -n root vgx >&2 yes | lvcreate -L ${size_root_lv}G -n root vgx >&2
echo "done." echo "done."
echo -n "Creating filesystem on root logical volume (ext4)... " echo -n "Creating filesystem on root logical volume (ext4)... "
yes | mkfs.ext4 /dev/vgx/root >&2 yes | mkfs.ext4 /dev/vgx/root >&2
@ -392,18 +553,18 @@ echo -n "Creating ceph logical volume (${size_ceph_lv}GB)... "
yes | lvcreate -L ${size_ceph_lv}G -n ceph vgx >&2 yes | lvcreate -L ${size_ceph_lv}G -n ceph vgx >&2
echo "done." echo "done."
echo -n "Creating filesystem on ceph logical volume (ext4)... " echo -n "Creating filesystem on ceph logical volume (ext4)... "
mkfs.ext4 /dev/vgx/ceph >&2 yes | mkfs.ext4 /dev/vgx/ceph >&2
echo "done." echo "done."
echo -n "Creating zookeeper logical volume (${size_zookeeper_lv}GB)... " echo -n "Creating zookeeper logical volume (${size_zookeeper_lv}GB)... "
yes | lvcreate -L ${size_zookeeper_lv}G -n zookeeper vgx >&2 yes | lvcreate -L ${size_zookeeper_lv}G -n zookeeper vgx >&2
echo "done." echo "done."
echo -n "Creating filesystem on zookeeper logical volume (ext4)... " echo -n "Creating filesystem on zookeeper logical volume (ext4)... "
mkfs.ext4 /dev/vgx/zookeeper >&2 yes | mkfs.ext4 /dev/vgx/zookeeper >&2
echo "done." echo "done."
echo -n "Creating swap logical volume (${size_swap_lv}GB)... " echo -n "Creating swap logical volume (${size_swap_lv}GB)... "
lvcreate -L ${size_swap_lv}G -n swap vgx >&2 yes | lvcreate -L ${size_swap_lv}G -n swap vgx >&2
echo "done." echo "done."
echo -n "Creating swap space on swap logical volume... " echo -n "Creating swap space on swap logical volume... "
yes | mkswap -f /dev/vgx/swap >&2 yes | mkswap -f /dev/vgx/swap >&2
@ -417,8 +578,10 @@ echo -n "Creating filesystem on ESP partition (vfat)... "
yes | mkdosfs -F32 ${target_disk}1 >&2 yes | mkdosfs -F32 ${target_disk}1 >&2
echo "done." echo "done."
echo -n "Mounting disks on temporary target... " vgchange -ay >&2
target=$( mktemp -d ) target="/tmp/target"
mkdir -p ${target} >&2
echo -n "Mounting disks on temporary target '${target}'... "
mount /dev/vgx/root ${target} >&2 mount /dev/vgx/root ${target} >&2
mkdir -p ${target}/boot >&2 mkdir -p ${target}/boot >&2
chattr +i ${target}/boot >&2 chattr +i ${target}/boot >&2
@ -438,7 +601,8 @@ mount -t tmpfs tmpfs ${target}/tmp >&2
echo "done." echo "done."
echo -n "Running debootstrap install... " echo -n "Running debootstrap install... "
debootstrap --include=${debpkglist} ${debrelease} ${target}/ ${debmirror} >&2 echo "Command: debootstrap --include=${inclpkglist} ${debrelease} ${target}/ ${debmirror}" >&2
debootstrap --include=${inclpkglist} ${debrelease} ${target}/ ${debmirror} >&2
echo "done." echo "done."
echo -n "Adding non-free repository (firmware, etc.)... " echo -n "Adding non-free repository (firmware, etc.)... "
@ -453,7 +617,7 @@ echo "done."
# Determine the bypath name of the specified system disk # Determine the bypath name of the specified system disk
for disk in /dev/disk/by-path/*; do for disk in /dev/disk/by-path/*; do
bypathlink="$( readlink ${disk} | awk -F'/' '{ print $NF }' )" bypathlink="$( realpath ${disk} | awk -F'/' '{ print $NF }' )"
enteredname="$( awk -F'/' '{ print $NF }' <<<"${target_disk}" )" enteredname="$( awk -F'/' '{ print $NF }' <<<"${target_disk}" )"
if [[ ${bypathlink} == ${enteredname} ]]; then if [[ ${bypathlink} == ${enteredname} ]]; then
bypath_disk="${disk}" bypath_disk="${disk}"
@ -470,8 +634,94 @@ echo "${bypath_disk}-part1 /boot/efi vfat umask=0077 0 2" | tee -a ${target}/etc
echo "tmpfs /tmp tmpfs defaults 0 0" | tee -a ${target}/etc/fstab >&2 echo "tmpfs /tmp tmpfs defaults 0 0" | tee -a ${target}/etc/fstab >&2
echo "done." echo "done."
echo -n "Adding interface segment... " seed_interfaces_segment() {
echo -e "${target_interfaces_block}" | tee -a ${target}/etc/network/interfaces >&2 # 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 "done."
echo -n "Setting temporary 'root' password... " echo -n "Setting temporary 'root' password... "
@ -480,14 +730,21 @@ echo "done."
echo -n "Adding deployment user... " echo -n "Adding deployment user... "
mv ${target}/home ${target}/var/home >&2 mv ${target}/home ${target}/var/home >&2
chroot ${target} useradd -u 200 -d /var/home/XXDEPLOYUSERXX -m -s /bin/bash -g operator -G sudo XXDEPLOYUSERXX >&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/XXDEPLOYUSERXX/.ssh chroot ${target} mkdir -p /var/home/${target_deploy_user}/.ssh
if [[ -n ${target_keys_url} ]]; then if [[ -n ${target_keys_path} ]]; then
wget -O ${target}/var/home/XXDEPLOYUSERXX/.ssh/authorized_keys ${target_keys_url} case ${target_keys_method} in
chroot ${target} chmod 0600 /var/home/XXDEPLOYUSERXX/.ssh/authorized_keys wget)
chroot ${target} chown -R XXDEPLOYUSERXX:operator /var/home/XXDEPLOYUSERXX 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 else
echo "XXDEPLOYUSERXX:${target_password}" | chroot ${target} chpasswd >&2 echo "${target_deploy_user}:${target_password}" | chroot ${target} chpasswd >&2
fi fi
echo "done." echo "done."
@ -498,11 +755,11 @@ echo "done."
echo -n "Setting /etc/issue generator... " echo -n "Setting /etc/issue generator... "
mkdir -p ${target}/etc/network/if-up.d >&2 mkdir -p ${target}/etc/network/if-up.d >&2
echo -e "#!/bin/sh echo -e "#!/bin/sh
IP=\"\$( ip -4 addr show dev ${real_interface} | grep inet | awk '{ print \$2 }' | head -1 )\" IP=\"\$( ip -4 addr show dev ${target_interface} | grep inet | awk '{ print \$2 }' | head -1 )\"
cat <<EOF >/etc/issue cat <<EOF >/etc/issue
Debian GNU/Linux 10 \\\\n \\\\l Debian GNU/Linux 10 \\\\n \\\\l
Primary interface IP address: \$IP Bootstrap interface IP address: \$IP
EOF" | tee ${target}/etc/network/if-up.d/issue-gen >&2 EOF" | tee ${target}/etc/network/if-up.d/issue-gen >&2
chmod +x ${target}/etc/network/if-up.d/issue-gen 1>&2 chmod +x ${target}/etc/network/if-up.d/issue-gen 1>&2
@ -533,10 +790,36 @@ if [[ -d /sys/firmware/efi ]]; then
else else
bios_target="i386-pc" bios_target="i386-pc"
fi 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-install --force --target=${bios_target} ${target_disk} >&2
chroot ${target} grub-mkconfig -o /boot/grub/grub.cfg >&2 chroot ${target} grub-mkconfig -o /boot/grub/grub.cfg >&2
echo "done." 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 set +o errexit
echo 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] " 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] "
@ -567,3 +850,13 @@ echo
read read
reboot reboot
}
case ${install_option} in
on)
seed_postinst
;;
*)
interactive_postinst
;;
esac

0
pxelinux.0 Normal file
View File