|
|
- #!/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" <<EOF
- #!ipxe
- dhcp
- set farm ${FARM}
- chain https://bootstrap.grid.tf/uefi/${ENVIRONMENT}/\${FARM}/debug/zero-os-development-zos-v4-debug-7d2de62033.efi?version=v4"
- # chain https://bootstrap.grid.tf/ipxe/${ENVIRONMENT}/\${farm}
- EOF
-
- log "iPXE script created at ${MOUNT_POINT}/boot.ipxe"
-
- # Unmount the partition
- log "Unmounting ${MOUNT_POINT}..."
- umount "${MOUNT_POINT}" || {
- log "Failed to unmount ${MOUNT_POINT}."
- exit 1
- }
-
- log "Operation completed successfully."
- }
-
- # Execute the main function
- main "$@"
|