|
@@ -0,0 +1,269 @@ |
|
|
|
|
|
#!/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 "$@" |