Work on modular installer
This commit is contained in:
		
							
								
								
									
										35
									
								
								install.seed.example
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								install.seed.example
									
									
									
									
									
										Normal 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" | ||||
							
								
								
									
										298
									
								
								install.sh
									
									
									
									
									
								
							
							
						
						
									
										298
									
								
								install.sh
									
									
									
									
									
								
							| @@ -6,10 +6,13 @@ if [[ $( whoami ) != "root" ]]; then | ||||
|     exit 1 | ||||
| fi | ||||
|  | ||||
| logfile="/tmp/pvc-install.log" | ||||
| iso_name="XXDATEXX" | ||||
| target_deploy_user="XXDEPLOYUSERXX" | ||||
|  | ||||
| supported_debrelease="buster bullseye" | ||||
| default_debrelease="buster" | ||||
| 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" | ||||
|  | ||||
| @@ -20,22 +23,96 @@ suppkglist="firmware-linux,firmware-linux-nonfree,firmware-bnx2,firmware-bnx2x" | ||||
| # roles will overwrite it by default during configuration. | ||||
| root_password="hCb1y2PF" | ||||
|  | ||||
| clear | ||||
| # Obtain the mode from the kernel command line | ||||
| kernel_cmdline=$( cat /proc/cmdline ) | ||||
| install_option="$( awk '{ | ||||
|     for(i=1; i<=NF; i++) { | ||||
|         if($i ~ /pvcinstall.preseed/) { | ||||
|             print $i; | ||||
|         } | ||||
|     } | ||||
| }' <<<"${kernel_cmdline}" | awk -F'=' '{ print $NF }' )" | ||||
|  | ||||
| echo "--------------------------------------------------------" | ||||
| echo "| PVC Node installer (XXDATEXX) |" | ||||
| 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 | ||||
| seed_config() { | ||||
|     echo "Hello ${1}" | ||||
|     seed_vlan="$( awk '{ | ||||
|         for(i=1; i<=NF; i++) { | ||||
|             if($i ~ /pvcinstall.seed_vlan/) { | ||||
|                 print $i; | ||||
|             } | ||||
|         } | ||||
|     }' <<<"${kernel_cmdline}" | awk -F'=' '{ print $NF }' )" | ||||
|     seed_host="$( awk '{ | ||||
|         for(i=1; i<=NF; i++) { | ||||
|             if($i ~ /pvcinstall.seed_host/) { | ||||
|                 print $i; | ||||
|             } | ||||
|         } | ||||
|     }' <<<"${kernel_cmdline}" | awk -F'=' '{ print $NF }' )" | ||||
|     seed_file="$( awk '{ | ||||
|         for(i=1; i<=NF; i++) { | ||||
|             if($i ~ /pvcinstall.seed_file/) { | ||||
|                 print $i; | ||||
|             } | ||||
|         } | ||||
|     }' <<<"${kernel_cmdline}" | awk -F'=' '{ print $NF }' )" | ||||
|  | ||||
| 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 | ||||
|     if [[ -n ${seed_vlan} ]]; then | ||||
|         modprobe 8021q | ||||
|     fi | ||||
|  | ||||
|     # 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 | ||||
|         if [[ -n ${seed_vlan} ]]; then | ||||
|             vconfig add ${interface} ${seed_vlan} | ||||
|             dhclient ${interface}.${seed_vlan} | ||||
|         else | ||||
|             dhclient ${interface} | ||||
|         fi | ||||
|     done | ||||
|  | ||||
|     # Fetch the seed config | ||||
|     tftp -m binary "${seed_host}" -c get "${seed_file}" /tmp/install.seed | ||||
|  | ||||
|     . /tmp/install.seed | ||||
|  | ||||
|     # Handle the target disk | ||||
|     if [[ -n ${target_disk_path} ]]; then | ||||
|         target_disk="$( readlink ${target_disk_path} )" | ||||
|         if [[ ! -b ${target_disk} ]]; then | ||||
|             echo "Invalid disk!" | ||||
|             exit 1 | ||||
|         fi | ||||
|     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 | ||||
| } | ||||
|  | ||||
| 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 | ||||
| @@ -45,9 +122,9 @@ while [[ -z ${target_hostname} ]]; do | ||||
|             continue | ||||
|         fi | ||||
|         echo | ||||
| done | ||||
|     done | ||||
|      | ||||
| disks="$( | ||||
|     disks="$( | ||||
|         for disk in /dev/sd? /dev/nvme?n?; do | ||||
|             if [[ ! -b ${disk} ]]; then | ||||
|                 continue | ||||
| @@ -58,20 +135,20 @@ disks="$( | ||||
|             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 "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 | ||||
| @@ -89,23 +166,23 @@ while [[ ! -b ${target_disk} ]]; do | ||||
|             continue | ||||
|         fi | ||||
|         echo | ||||
| done | ||||
|     done | ||||
|      | ||||
| for interface in $( ip address | grep '^[0-9]' | grep 'eno\|enp\|ens\|wlp' | awk '{ print $2 }' | tr -d ':' ); do | ||||
|     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="$( | ||||
|     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 "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 | ||||
| @@ -121,11 +198,11 @@ while [[ -z ${target_interface} ]]; do | ||||
|             continue | ||||
|         fi | ||||
|         echo | ||||
| done | ||||
|     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 -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 | ||||
| @@ -139,17 +216,17 @@ if [[ ${vlans_req} == 'y' || ${vlans_req} == 'Y' ]]; then | ||||
|             fi | ||||
|         done | ||||
|         echo | ||||
| else | ||||
|     else | ||||
|         vlan_id="" | ||||
|         echo | ||||
| fi | ||||
|     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 | ||||
|     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" | ||||
| @@ -165,13 +242,13 @@ if [[ -n ${target_ipaddr} ]]; then | ||||
|             fi | ||||
|             echo | ||||
|         done | ||||
| else | ||||
|     else | ||||
|         target_netformat="dhcp" | ||||
|         echo | ||||
| fi | ||||
|     fi | ||||
|      | ||||
| echo -n "Bringing up primary network interface in ${target_netformat} mode... " | ||||
| case ${target_netformat} in | ||||
|     echo -n "Bringing up primary network interface in ${target_netformat} mode... " | ||||
|     case ${target_netformat} in | ||||
|         'static') | ||||
|             if [[ -n ${vlan_id} ]]; then | ||||
|                 modprobe 8021q >&2 | ||||
| @@ -212,21 +289,21 @@ EOF | ||||
|                 real_interface="${target_interface}" | ||||
|             fi | ||||
|         ;; | ||||
| esac | ||||
| echo "done." | ||||
| echo | ||||
|     esac | ||||
|     echo "done." | ||||
|     echo | ||||
|      | ||||
| echo -n "Waiting for networking to become ready... " | ||||
| while ! ping -q -c 1 8.8.8.8 &>/dev/null; do | ||||
|     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 | ||||
|     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 "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 | ||||
| @@ -240,11 +317,11 @@ while [[ -z ${debrelease} ]]; do | ||||
|             continue | ||||
|         fi | ||||
|         echo | ||||
| done | ||||
|     done | ||||
|      | ||||
| echo "4b) Please enter an HTTP URL for an alternate Debian mirror if desired." | ||||
| echo "    Default: ${default_debmirror}" | ||||
| while [[ -z ${debmirror} ]]; do | ||||
|     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 | ||||
| @@ -260,21 +337,22 @@ while [[ -z ${debmirror} ]]; do | ||||
|         echo | ||||
|         echo "Repository mirror '${debmirror}' successfully validated." | ||||
|         echo | ||||
| done | ||||
|     done | ||||
|      | ||||
| 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_url | ||||
| if [[ -z ${target_keys_url} ]]; then | ||||
|     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 'XXDEPLOYUSERXX'." | ||||
|         echo "5) Please enter a password (hidden), twice, for the deployment user '${target_deploy_user}'." | ||||
|         while [[ -z "${target_password}" ]]; do | ||||
|             echo | ||||
|             echo -n "> " | ||||
| @@ -290,18 +368,29 @@ if [[ -z ${target_keys_url} ]]; then | ||||
|                 echo "The specified passwords do not match or are empty." | ||||
|             fi | ||||
|         done | ||||
| else | ||||
|     while ! wget -O /dev/null ${target_keys_url} &>/dev/null; do | ||||
|     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_url | ||||
|             read target_keys_path | ||||
|         done | ||||
|         echo | ||||
|     echo "SSH key source '${target_keys_url}' successfully validated." | ||||
| fi | ||||
| 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 ))" | ||||
| @@ -314,6 +403,8 @@ echo | ||||
| echo "LOGFILE: ${logfile}" | ||||
| echo | ||||
|  | ||||
| exit 0 | ||||
|  | ||||
| set -o errexit | ||||
| exec 1> >( tee -ia ${logfile} ) | ||||
| exec 2> >( tee -ia ${logfile} >/dev/null ) | ||||
| @@ -480,14 +571,21 @@ echo "done." | ||||
|  | ||||
| echo -n "Adding deployment user... " | ||||
| 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} mkdir -p /var/home/XXDEPLOYUSERXX/.ssh | ||||
| if [[ -n ${target_keys_url} ]]; then | ||||
| wget -O ${target}/var/home/XXDEPLOYUSERXX/.ssh/authorized_keys ${target_keys_url} | ||||
| chroot ${target} chmod 0600 /var/home/XXDEPLOYUSERXX/.ssh/authorized_keys | ||||
| chroot ${target} chown -R XXDEPLOYUSERXX:operator /var/home/XXDEPLOYUSERXX | ||||
| 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 "XXDEPLOYUSERXX:${target_password}" | chroot ${target} chpasswd >&2 | ||||
|     echo "${target_deploy_user}:${target_password}" | chroot ${target} chpasswd >&2 | ||||
| fi | ||||
| echo "done." | ||||
|  | ||||
|   | ||||
							
								
								
									
										0
									
								
								pxelinux.0
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								pxelinux.0
									
									
									
									
									
										Normal file
									
								
							
		Reference in New Issue
	
	Block a user