|
- #!/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, nvme0n1)."
- 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 a suitable block device
- find_blockdev() {
- # Minimum size in bytes, e.g., 10 GiB
- MIN_SIZE=$((10 * 1024 * 1024 * 1024))
-
- # Search for NVMe devices first
- log "Searching for NVMe devices..."
- for DEV in /dev/nvme*n1; do
- if [ -b "$DEV" ]; then
- SIZE_BYTES=$(blockdev --getsize64 "$DEV")
- if [ "$SIZE_BYTES" -ge "$MIN_SIZE" ]; then
- log "Found NVMe device: $DEV ($(numfmt --to=iec $SIZE_BYTES))"
- BLOCKDEV="${DEV##*/}"
- return 0
- else
- log "$DEV is smaller than $(numfmt --to=iec $MIN_SIZE). Skipping."
- fi
- fi
- done
-
- # If no NVMe device found, search for SSD devices
- log "No suitable NVMe device found. Searching for SSD devices..."
- for DEV_PATH in /sys/block/*; do
- DEV_NAME=$(basename "$DEV_PATH")
- # Exclude unwanted devices
- case "$DEV_NAME" in
- loop* | ram* | sr* | fd* | md* | dm-*)
- 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))"
- BLOCKDEV="$DEV_NAME"
- return 0
- else
- log "$DEVICE is smaller than $(numfmt --to=iec $MIN_SIZE). Skipping."
- fi
- fi
- done
-
- log "No suitable block device found."
- return 1
- }
-
- # Function to manage UEFI boot entries
- manage_boot_entries() {
- log "Managing UEFI boot entries..."
-
- # Check if efibootmgr is available
- if ! command -v efibootmgr &>/dev/null; then
- log "Error: 'efibootmgr' is not installed. Please install it and rerun the script."
- exit 1
- fi
-
- # Get the list of current boot entries
- log "Retrieving current boot entries..."
- BOOT_ENTRIES_INFO=$(efibootmgr -v | grep -E "^Boot[0-9A-F]{4}")
-
- # Arrays to hold boot entry numbers
- NETBOOT_ENTRIES=()
- ENTRIES_TO_DELETE=()
-
- # Identify netboot entries and entries to delete
- while read -r LINE; do
- ENTRY_NUM=$(echo "$LINE" | awk '{print $1}' | sed 's/Boot//;s/\*//')
- ENTRY_DESC=$(echo "$LINE" | cut -d' ' -f2-)
- ENTRY_PATH=$(echo "$LINE" | awk -F'File' '{print $2}')
-
- # Check if the entry is a netboot entry (e.g., contains "PXE", "Network", or "IPv4"/"IPv6")
- if echo "$ENTRY_DESC" | grep -qiE "(PXE|Network|IPV4|IPV6)"; then
- NETBOOT_ENTRIES+=("$ENTRY_NUM")
- log "Identified netboot entry: Boot$ENTRY_NUM - $ENTRY_DESC"
- else
- ENTRIES_TO_DELETE+=("$ENTRY_NUM")
- log "Marking entry for deletion: Boot$ENTRY_NUM - $ENTRY_DESC"
- fi
- done <<<"$BOOT_ENTRIES_INFO"
-
- # Delete non-netboot entries
- if [ ${#ENTRIES_TO_DELETE[@]} -gt 0 ]; then
- log "Deleting non-netboot boot entries..."
- for ENTRY_NUM in "${ENTRIES_TO_DELETE[@]}"; do
- efibootmgr -b "$ENTRY_NUM" -B
- log "Deleted boot entry Boot$ENTRY_NUM"
- done
- else
- log "No non-netboot entries to delete."
- fi
-
- # Create a new boot entry pointing to BOOTX64.EFI on the first partition
- log "Creating new boot entry for /dev/${PARTPREFIX}1..."
- # Adjust the partition number if necessary
- ESP_PART_NUM=1
- efibootmgr -c -d /dev/${BLOCKDEV} -p $ESP_PART_NUM -L "Zero-OS" -l "\\EFI\\BOOT\\BOOTX64.EFI" || {
- log "Error: Failed to create new boot entry."
- exit 1
- }
-
- # Retrieve the new boot entry number
- NEW_BOOT_NUM=$(efibootmgr | grep "Zero-OS" | awk '{print $1}' | sed 's/\*//;s/Boot//')
- if [ -z "$NEW_BOOT_NUM" ]; then
- log "Error: Failed to retrieve new boot entry number."
- exit 1
- fi
-
- # Set the new boot order: netboot entries first, followed by the new boot entry
- log "Setting new BootOrder with netboot entries first..."
- BOOT_ORDER=""
- for ENTRY_NUM in "${NETBOOT_ENTRIES[@]}"; do
- BOOT_ORDER+="$ENTRY_NUM,"
- done
- BOOT_ORDER+="$NEW_BOOT_NUM"
-
- efibootmgr -o "$BOOT_ORDER" || {
- log "Error: Failed to set new BootOrder."
- exit 1
- }
-
- log "New BootOrder set successfully: $BOOT_ORDER"
- }
-
- # 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##*/}"
- log "Using specified block device: $BLOCKDEV_SPECIFIED"
- else
- # Find a suitable block device
- if ! find_blockdev; then
- log "Error: No suitable block device found."
- exit 1
- fi
- log "Selected block device: /dev/${BLOCKDEV}"
- fi
-
- # Confirm with the user before proceeding
- read -p "This will erase all data on /dev/${BLOCKDEV}. Are you sure you want to proceed? (yes/[no]): " CONFIRM
- if [ "$CONFIRM" != "yes" ]; then
- log "Operation cancelled by user."
- exit 0
- fi
-
- # Determine partition naming convention
- if [[ $BLOCKDEV =~ [0-9]$ ]]; then
- PARTPREFIX="${BLOCKDEV}p"
- else
- PARTPREFIX="${BLOCKDEV}"
- fi
-
- # Wipe filesystem signatures
- log "Wiping filesystem signatures on /dev/${BLOCKDEV}..."
- wipefs -a -f /dev/${BLOCKDEV} || {
- log "Failed to wipe filesystem signatures."
- exit 1
- }
-
- # Create GPT partition table
- log "Creating GPT partition table on /dev/${BLOCKDEV}..."
- parted -s /dev/${BLOCKDEV} mklabel gpt || {
- log "Failed to create GPT partition table."
- exit 1
- }
-
- # Create partitions
- log "Creating partitions on /dev/${BLOCKDEV}..."
- if ! parted -s /dev/${BLOCKDEV} "mkpart zosboot fat16 1MiB 100MiB set 1 esp on mkpart zoscache btrfs 100MiB 100%"; then
- log "Failed to create partitions."
- exit 1
- fi
-
- # Format partitions
- log "Formatting /dev/${PARTPREFIX}1 as FAT32..."
- if ! mkfs.vfat -F32 -nZOSPXE /dev/${PARTPREFIX}1; then
- log "Failed to format /dev/${PARTPREFIX}1 as FAT32."
- exit 1
- fi
-
- log "Formatting /dev/${PARTPREFIX}2 as BTRFS..."
- if ! mkfs.btrfs -f /dev/${PARTPREFIX}2 -LZOSCACHE; then
- log "Failed to format /dev/${PARTPREFIX}2 as BTRFS."
- exit 1
- fi
-
- # Mount and prepare directories
- MOUNT_POINT="zospxe"
- log "Creating and mounting directory ./${MOUNT_POINT}..."
- mkdir -p "${MOUNT_POINT}"
- if ! mount /dev/${PARTPREFIX}1 -t vfat "${MOUNT_POINT}"; then
- log "Failed to mount /dev/${PARTPREFIX}1 to ${MOUNT_POINT}."
- exit 1
- fi
-
- log "Creating directory structure in ${MOUNT_POINT}..."
- mkdir -p "${MOUNT_POINT}/efi/boot"
-
- # Download the required BOOTX64.EFI file
- EFI_FILE_URL="https://bootstrap.grid.tf/uefi/${ENVIRONMENT}/${FARM}"
- log "Downloading BOOTX64.EFI from ${EFI_FILE_URL}..."
- if ! wget -q "${EFI_FILE_URL}" -O "${MOUNT_POINT}/efi/boot/BOOTX64.EFI"; then
- log "Failed to download BOOTX64.EFI."
- exit 1
- fi
-
- log "Download successful."
-
- # Unmount the partition
- log "Unmounting ${MOUNT_POINT}..."
- umount -r "${MOUNT_POINT}" || {
- log "Failed to unmount ${MOUNT_POINT}."
- exit 1
- }
-
- # Manage UEFI boot entries
- manage_boot_entries
-
- log "Operation completed successfully."
- }
-
- # Execute the main function
- main "$@"
|