From b593f1a54e7772a4dc1af4bc843a078ea6790f3f Mon Sep 17 00:00:00 2001 From: Jan De Landtsheer Date: Thu, 12 Dec 2024 13:26:01 +0100 Subject: [PATCH] Added BIOS-capable installer --- zosinstallBIOSipxeondisk.sh | 294 ++++++++++++++++++++++++++++++++++++ 1 file changed, 294 insertions(+) create mode 100644 zosinstallBIOSipxeondisk.sh diff --git a/zosinstallBIOSipxeondisk.sh b/zosinstallBIOSipxeondisk.sh new file mode 100644 index 0000000..da353be --- /dev/null +++ b/zosinstallBIOSipxeondisk.sh @@ -0,0 +1,294 @@ +#!/bin/bash + +# Enable strict error handling +set -e + +# Function to log messages with timestamps +log() { + echo "$(date '+%F %T') - $@" +} + +# Function to display usage information +usage() { + echo "Usage: $0 [-d DEVICE] [-f FARM] [-e ENVIRONMENT]" + echo " -d, --device DEVICE Specify the block device to use (e.g., sda, sdb)." + echo " -f, --farm FARM Specify the FARM ID." + echo " -e, --environment ENV Specify the environment (dev, qa, test, prod)." + echo " -h, --help Display this help message." + exit 1 +} + +# Function to find suitable block devices +find_blockdev() { + # Minimum size in bytes, e.g., 10 GiB + MIN_SIZE=$((10 * 1024 * 1024 * 1024)) + + BLOCKDEVICES=() + + # Exclude the boot disk + BOOT_DISK=$(findmnt -n -o SOURCE / | sed 's/[0-9]*$//;s|^/dev/||') + log "Boot disk detected: /dev/${BOOT_DISK}" + + # Search for NVMe devices first + log "Searching for NVMe devices..." + for DEV in /dev/nvme*n1; do + DEV_BASE=$(basename "$DEV") + if [ -b "$DEV" ] && [ "$DEV_BASE" != "$BOOT_DISK" ]; then + SIZE_BYTES=$(blockdev --getsize64 "$DEV") + if [ "$SIZE_BYTES" -ge "$MIN_SIZE" ]; then + log "Found NVMe device: $DEV ($(numfmt --to=iec $SIZE_BYTES))" + BLOCKDEVICES+=("$DEV_BASE") + else + log "$DEV is smaller than $(numfmt --to=iec $MIN_SIZE). Skipping." + fi + else + [ "$DEV_BASE" == "$BOOT_DISK" ] && log "Skipping boot disk: $DEV" + fi + done + + # Search for SSD devices + log "Searching for SSD devices..." + for DEV_PATH in /sys/block/*; do + DEV_NAME=$(basename "$DEV_PATH") + # Exclude unwanted devices and the boot disk + case "$DEV_NAME" in + loop* | ram* | sr* | fd* | md* | dm-*) + continue + ;; + "$BOOT_DISK") + log "Skipping boot disk: /dev/$DEV_NAME" + continue + ;; + esac + DEVICE="/dev/$DEV_NAME" + if [ -b "$DEVICE" ] && [ -e "/sys/block/$DEV_NAME/queue/rotational" ] && [ "$(cat /sys/block/$DEV_NAME/queue/rotational)" == "0" ]; then + SIZE_BYTES=$(blockdev --getsize64 "$DEVICE") + if [ "$SIZE_BYTES" -ge "$MIN_SIZE" ]; then + log "Found SSD device: $DEVICE ($(numfmt --to=iec $SIZE_BYTES))" + BLOCKDEVICES+=("$DEV_NAME") + else + log "$DEVICE is smaller than $(numfmt --to=iec $MIN_SIZE). Skipping." + fi + fi + done + + if [ ${#BLOCKDEVICES[@]} -eq 0 ]; then + log "No suitable block devices found." + return 1 + fi + + log "List of block devices to be wiped:" + for DEV in "${BLOCKDEVICES[@]}"; do + log "/dev/$DEV" + done + + # Select the first device as the block device to partition + BLOCKDEV="${BLOCKDEVICES[0]}" +} + +# Main script execution +main() { + # Default values + BLOCKDEV_SPECIFIED="" + FARM="1234" + ENVIRONMENT="prod" + + # Parse command-line arguments + while [[ $# -gt 0 ]]; do + case "$1" in + -d | --device) + shift + if [ -z "$1" ]; then + log "Error: '--device' requires a non-empty option argument." + usage + fi + BLOCKDEV_SPECIFIED="$1" + shift + ;; + -f | --farm) + shift + if [ -z "$1" ]; then + log "Error: '--farm' requires a non-empty option argument." + usage + fi + FARM="$1" + shift + ;; + -e | --environment) + shift + if [ -z "$1" ]; then + log "Error: '--environment' requires a non-empty option argument." + usage + fi + ENVIRONMENT="$1" + shift + ;; + -h | --help) + usage + ;; + *) + log "Error: Unknown option: $1" + usage + ;; + esac + done + + # Validate environment + case "$ENVIRONMENT" in + dev | qa | test | prod) + log "Using environment: $ENVIRONMENT" + ;; + *) + log "Error: Invalid environment '$ENVIRONMENT'. Valid options are 'dev', 'qa', 'test', 'prod'." + exit 1 + ;; + esac + + if [ -n "$BLOCKDEV_SPECIFIED" ]; then + # Use the specified block device + if [[ "$BLOCKDEV_SPECIFIED" != /dev/* ]]; then + BLOCKDEV_SPECIFIED="/dev/$BLOCKDEV_SPECIFIED" + fi + if [ ! -b "$BLOCKDEV_SPECIFIED" ]; then + log "Error: Specified device $BLOCKDEV_SPECIFIED does not exist or is not a block device." + exit 1 + fi + BLOCKDEV="${BLOCKDEV_SPECIFIED##*/}" + BLOCKDEVICES=("$BLOCKDEV") + log "Using specified block device: $BLOCKDEV_SPECIFIED" + else + # Find suitable block devices + if ! find_blockdev; then + log "Error: No suitable block devices found." + exit 1 + fi + fi + + # Confirm with the user before proceeding + log "The following disks will be wiped:" + for DEV in "${BLOCKDEVICES[@]}"; do + log "/dev/$DEV" + done + read -p "This will erase all data on the above disks. Are you sure you want to proceed? Type 'WIPE ALL' to confirm: " CONFIRM + if [ "$CONFIRM" != "WIPE ALL" ]; then + log "Operation cancelled by user." + exit 0 + fi + + # Wipe filesystem signatures on all disks + log "Wiping filesystem signatures on all selected disks..." + for DEV in "${BLOCKDEVICES[@]}"; do + log "Wiping /dev/$DEV..." + wipefs -a -f /dev/$DEV || { + log "Failed to wipe /dev/$DEV" + exit 1 + } + done + + # Proceed with partitioning and formatting the first disk + # Determine partition naming convention + if [[ $BLOCKDEV =~ [0-9]$ ]]; then + PARTPREFIX="${BLOCKDEV}p" + else + PARTPREFIX="${BLOCKDEV}" + fi + + # Create GPT partition table on the selected block device + log "Creating GPT partition table on /dev/${BLOCKDEV}..." + parted -s /dev/${BLOCKDEV} mklabel gpt || { + log "Failed to create GPT partition table." + exit 1 + } + + # Create BIOS Boot Partition + log "Creating BIOS Boot partition on /dev/${BLOCKDEV}..." + parted -s /dev/${BLOCKDEV} mkpart primary 1MiB 2MiB || { + log "Failed to create BIOS Boot partition." + exit 1 + } + parted -s /dev/${BLOCKDEV} set 1 bios_grub on + + # Create additional partitions as needed + log "Creating data partitions on /dev/${BLOCKDEV}..." + parted -s /dev/${BLOCKDEV} mkpart primary 2MiB 100MiB || { + log "Failed to create partition." + exit 1 + } + parted -s /dev/${BLOCKDEV} mkpart primary 100MiB 100% || { + log "Failed to create partition." + exit 1 + } + + # Format partitions + log "Formatting /dev/${PARTPREFIX}2 as FAT16..." + if ! mkfs.vfat -F16 /dev/${PARTPREFIX}2; then + log "Failed to format /dev/${PARTPREFIX}2 as FAT16." + exit 1 + fi + + log "Formatting /dev/${PARTPREFIX}3 as BTRFS..." + if ! mkfs.btrfs -f /dev/${PARTPREFIX}3; then + log "Failed to format /dev/${PARTPREFIX}3 as BTRFS." + exit 1 + fi + + # Install iPXE bootloader to MBR + log "Installing iPXE bootloader to MBR of /dev/${BLOCKDEV}..." + + # Download the iPXE bootloader suitable for BIOS + log "Downloading iPXE bootloader..." + if ! wget -q -O ipxe.lkrn http://boot.ipxe.org/ipxe.lkrn; then + log "Failed to download iPXE bootloader." + exit 1 + fi + + # Write iPXE bootloader to the MBR + log "Writing iPXE bootloader to MBR of /dev/${BLOCKDEV}..." + dd if=ipxe.lkrn of=/dev/${BLOCKDEV} bs=440 count=1 conv=notrunc || { + log "Failed to write iPXE to MBR." + exit 1 + } + + # Clean up the downloaded file + rm -f ipxe.lkrn + + # Prepare the iPXE script + log "Preparing iPXE script..." + + # Mount the FAT16 partition to store the iPXE script + MOUNT_POINT="zospxe" + log "Creating and mounting directory ./${MOUNT_POINT}..." + mkdir -p "${MOUNT_POINT}" + if ! mount /dev/${PARTPREFIX}2 -t vfat "${MOUNT_POINT}"; then + log "Failed to mount /dev/${PARTPREFIX}2 to ${MOUNT_POINT}." + exit 1 + fi + + # Download the BOOTX64.EFI file (optional, depending on your setup) + # Since this is a BIOS system, we might not need this step + # However, if required, adjust the script accordingly + + # Alternatively, create an embedded iPXE script + log "Creating iPXE script..." + cat >"${MOUNT_POINT}/boot.ipxe" <