|
- #!/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
- CURRENT_BOOT_ENTRIES=$(efibootmgr | grep "BootOrder")
- log "Current BootOrder: $CURRENT_BOOT_ENTRIES"
-
- # Delete all existing boot entries except the EFI Shell (if present)
- log "Deleting existing boot entries..."
- BOOT_ENTRIES=$(efibootmgr | grep -E "^Boot[0-9A-F]{4}" | awk '{print $1}' | sed 's/\*//')
- for ENTRY in $BOOT_ENTRIES; do
- efibootmgr -b ${ENTRY#Boot} -B
- log "Deleted boot entry $ENTRY"
- done
-
- # 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
- }
-
- # Set the boot order to include only the new boot entry
- 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
- log "Setting BootOrder to only include Boot$NEW_BOOT_NUM..."
- efibootmgr -o $NEW_BOOT_NUM || {
- log "Error: Failed to set new BootOrder."
- exit 1
- }
-
- log "New BootOrder set successfully."
- }
-
- # 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 fat32 1MiB 300MiB set 1 esp on mkpart zoscache btrfs 300MiB 100%"; then
- log "Failed to create partitions."
- exit 1
- fi
-
- # Format partitions
- log "Formatting /dev/${PARTPREFIX}1 as FAT32..."
- if ! mkfs.vfat -F32 /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; 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
- # NOTE:: EDIT THIS WHEN APPROPRIATE AND IN PROD
- EFI_FILE_URL="https://bootstrap.grid.tf/uefi/${ENVIRONMENT}/${FARM}/debug/zero-os-development-zos-v4-debug-7d2de62033.efi?version=v4"
- # 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 "$@"
|