|
|
@@ -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" <<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 "$@" |