Public repo to distribute scripts and config's
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

270 lines
8.7 KiB

  1. #!/bin/bash
  2. # Enable strict error handling
  3. set -e
  4. # Function to log messages with timestamps
  5. log() {
  6. echo "$(date '+%F %T') - $@"
  7. }
  8. # Function to display usage information
  9. usage() {
  10. echo "Usage: $0 [-d DEVICE] [-f FARM] [-e ENVIRONMENT]"
  11. echo " -d, --device DEVICE Specify the block device to use (e.g., sda, nvme0n1)."
  12. echo " -f, --farm FARM Specify the FARM ID."
  13. echo " -e, --environment ENV Specify the environment (dev, qa, test, prod)."
  14. echo " -h, --help Display this help message."
  15. exit 1
  16. }
  17. # Function to find a suitable block device
  18. find_blockdev() {
  19. # Minimum size in bytes, e.g., 10 GiB
  20. MIN_SIZE=$((10 * 1024 * 1024 * 1024))
  21. # Search for NVMe devices first
  22. log "Searching for NVMe devices..."
  23. for DEV in /dev/nvme*n1; do
  24. if [ -b "$DEV" ]; then
  25. SIZE_BYTES=$(blockdev --getsize64 "$DEV")
  26. if [ "$SIZE_BYTES" -ge "$MIN_SIZE" ]; then
  27. log "Found NVMe device: $DEV ($(numfmt --to=iec $SIZE_BYTES))"
  28. BLOCKDEV="${DEV##*/}"
  29. return 0
  30. else
  31. log "$DEV is smaller than $(numfmt --to=iec $MIN_SIZE). Skipping."
  32. fi
  33. fi
  34. done
  35. # If no NVMe device found, search for SSD devices
  36. log "No suitable NVMe device found. Searching for SSD devices..."
  37. for DEV_PATH in /sys/block/*; do
  38. DEV_NAME=$(basename "$DEV_PATH")
  39. # Exclude unwanted devices
  40. case "$DEV_NAME" in
  41. loop*|ram*|sr*|fd*|md*|dm-*)
  42. continue
  43. ;;
  44. esac
  45. DEVICE="/dev/$DEV_NAME"
  46. if [ -b "$DEVICE" ] && [ -e "/sys/block/$DEV_NAME/queue/rotational" ] && [ "$(cat /sys/block/$DEV_NAME/queue/rotational)" == "0" ]; then
  47. SIZE_BYTES=$(blockdev --getsize64 "$DEVICE")
  48. if [ "$SIZE_BYTES" -ge "$MIN_SIZE" ]; then
  49. log "Found SSD device: $DEVICE ($(numfmt --to=iec $SIZE_BYTES))"
  50. BLOCKDEV="$DEV_NAME"
  51. return 0
  52. else
  53. log "$DEVICE is smaller than $(numfmt --to=iec $MIN_SIZE). Skipping."
  54. fi
  55. fi
  56. done
  57. log "No suitable block device found."
  58. return 1
  59. }
  60. # Function to manage UEFI boot entries
  61. manage_boot_entries() {
  62. log "Managing UEFI boot entries..."
  63. # Check if efibootmgr is available
  64. if ! command -v efibootmgr &> /dev/null; then
  65. log "Error: 'efibootmgr' is not installed. Please install it and rerun the script."
  66. exit 1
  67. fi
  68. # Get the list of current boot entries
  69. CURRENT_BOOT_ENTRIES=$(efibootmgr | grep "BootOrder")
  70. log "Current BootOrder: $CURRENT_BOOT_ENTRIES"
  71. # Delete all existing boot entries except the EFI Shell (if present)
  72. log "Deleting existing boot entries..."
  73. BOOT_ENTRIES=$(efibootmgr | grep -E "^Boot[0-9A-F]{4}" | awk '{print $1}' | sed 's/\*//')
  74. for ENTRY in $BOOT_ENTRIES; do
  75. efibootmgr -b ${ENTRY#Boot} -B
  76. log "Deleted boot entry $ENTRY"
  77. done
  78. # Create a new boot entry pointing to BOOTX64.EFI on the first partition
  79. log "Creating new boot entry for /dev/${PARTPREFIX}1..."
  80. # Adjust the partition number if necessary
  81. ESP_PART_NUM=1
  82. efibootmgr -c -d /dev/${BLOCKDEV} -p $ESP_PART_NUM -L "Zero-OS" -l "\\EFI\\BOOT\\BOOTX64.EFI" || {
  83. log "Error: Failed to create new boot entry."
  84. exit 1
  85. }
  86. # Set the boot order to include only the new boot entry
  87. NEW_BOOT_NUM=$(efibootmgr | grep "Zero-OS" | awk '{print $1}' | sed 's/\*//;s/Boot//')
  88. if [ -z "$NEW_BOOT_NUM" ]; then
  89. log "Error: Failed to retrieve new boot entry number."
  90. exit 1
  91. fi
  92. log "Setting BootOrder to only include Boot$NEW_BOOT_NUM..."
  93. efibootmgr -o $NEW_BOOT_NUM || {
  94. log "Error: Failed to set new BootOrder."
  95. exit 1
  96. }
  97. log "New BootOrder set successfully."
  98. }
  99. # Main script execution
  100. main() {
  101. # Default values
  102. BLOCKDEV_SPECIFIED=""
  103. FARM="1234"
  104. ENVIRONMENT="prod"
  105. # Parse command-line arguments
  106. while [[ $# -gt 0 ]]; do
  107. case "$1" in
  108. -d|--device)
  109. shift
  110. if [ -z "$1" ]; then
  111. log "Error: '--device' requires a non-empty option argument."
  112. usage
  113. fi
  114. BLOCKDEV_SPECIFIED="$1"
  115. shift
  116. ;;
  117. -f|--farm)
  118. shift
  119. if [ -z "$1" ]; then
  120. log "Error: '--farm' requires a non-empty option argument."
  121. usage
  122. fi
  123. FARM="$1"
  124. shift
  125. ;;
  126. -e|--environment)
  127. shift
  128. if [ -z "$1" ]; then
  129. log "Error: '--environment' requires a non-empty option argument."
  130. usage
  131. fi
  132. ENVIRONMENT="$1"
  133. shift
  134. ;;
  135. -h|--help)
  136. usage
  137. ;;
  138. *)
  139. log "Error: Unknown option: $1"
  140. usage
  141. ;;
  142. esac
  143. done
  144. # Validate environment
  145. case "$ENVIRONMENT" in
  146. dev|qa|test|prod)
  147. log "Using environment: $ENVIRONMENT"
  148. ;;
  149. *)
  150. log "Error: Invalid environment '$ENVIRONMENT'. Valid options are 'dev', 'qa', 'test', 'prod'."
  151. exit 1
  152. ;;
  153. esac
  154. if [ -n "$BLOCKDEV_SPECIFIED" ]; then
  155. # Use the specified block device
  156. if [[ "$BLOCKDEV_SPECIFIED" != /dev/* ]]; then
  157. BLOCKDEV_SPECIFIED="/dev/$BLOCKDEV_SPECIFIED"
  158. fi
  159. if [ ! -b "$BLOCKDEV_SPECIFIED" ]; then
  160. log "Error: Specified device $BLOCKDEV_SPECIFIED does not exist or is not a block device."
  161. exit 1
  162. fi
  163. BLOCKDEV="${BLOCKDEV_SPECIFIED##*/}"
  164. log "Using specified block device: $BLOCKDEV_SPECIFIED"
  165. else
  166. # Find a suitable block device
  167. if ! find_blockdev; then
  168. log "Error: No suitable block device found."
  169. exit 1
  170. fi
  171. log "Selected block device: /dev/${BLOCKDEV}"
  172. fi
  173. # Confirm with the user before proceeding
  174. read -p "This will erase all data on /dev/${BLOCKDEV}. Are you sure you want to proceed? (yes/[no]): " CONFIRM
  175. if [ "$CONFIRM" != "yes" ]; then
  176. log "Operation cancelled by user."
  177. exit 0
  178. fi
  179. # Determine partition naming convention
  180. if [[ $BLOCKDEV =~ [0-9]$ ]]; then
  181. PARTPREFIX="${BLOCKDEV}p"
  182. else
  183. PARTPREFIX="${BLOCKDEV}"
  184. fi
  185. # Wipe filesystem signatures
  186. log "Wiping filesystem signatures on /dev/${BLOCKDEV}..."
  187. wipefs -a -f /dev/${BLOCKDEV} || { log "Failed to wipe filesystem signatures."; exit 1; }
  188. # Create GPT partition table
  189. log "Creating GPT partition table on /dev/${BLOCKDEV}..."
  190. parted -s /dev/${BLOCKDEV} mklabel gpt || { log "Failed to create GPT partition table."; exit 1; }
  191. # Create partitions
  192. log "Creating partitions on /dev/${BLOCKDEV}..."
  193. if ! parted -s /dev/${BLOCKDEV} "mkpart zosboot fat32 1MiB 300MiB set 1 esp on mkpart zoscache btrfs 300MiB 100%"; then
  194. log "Failed to create partitions."
  195. exit 1
  196. fi
  197. # Format partitions
  198. log "Formatting /dev/${PARTPREFIX}1 as FAT32..."
  199. if ! mkfs.vfat -F32 /dev/${PARTPREFIX}1; then
  200. log "Failed to format /dev/${PARTPREFIX}1 as FAT32."
  201. exit 1
  202. fi
  203. log "Formatting /dev/${PARTPREFIX}2 as BTRFS..."
  204. if ! mkfs.btrfs -f /dev/${PARTPREFIX}2; then
  205. log "Failed to format /dev/${PARTPREFIX}2 as BTRFS."
  206. exit 1
  207. fi
  208. # Mount and prepare directories
  209. MOUNT_POINT="zospxe"
  210. log "Creating and mounting directory ./${MOUNT_POINT}..."
  211. mkdir -p "${MOUNT_POINT}"
  212. if ! mount /dev/${PARTPREFIX}1 -t vfat "${MOUNT_POINT}"; then
  213. log "Failed to mount /dev/${PARTPREFIX}1 to ${MOUNT_POINT}."
  214. exit 1
  215. fi
  216. log "Creating directory structure in ${MOUNT_POINT}..."
  217. mkdir -p "${MOUNT_POINT}/efi/boot"
  218. # Download the required BOOTX64.EFI file
  219. # NOTE:: EDIT THIS WHEN APPROPRIATE AND IN PROD
  220. EFI_FILE_URL="https://bootstrap.grid.tf/uefi/${ENVIRONMENT}/${FARM}/debug/zero-os-development-zos-v4-debug-7d2de62033.efi?version=v4"
  221. # EFI_FILE_URL="https://bootstrap.grid.tf/uefi/${ENVIRONMENT}/${FARM}"
  222. log "Downloading BOOTX64.EFI from ${EFI_FILE_URL}..."
  223. if ! wget -q "${EFI_FILE_URL}" -O "${MOUNT_POINT}/efi/boot/BOOTX64.EFI"; then
  224. log "Failed to download BOOTX64.EFI."
  225. exit 1
  226. fi
  227. log "Download successful."
  228. # Unmount the partition
  229. log "Unmounting ${MOUNT_POINT}..."
  230. umount -r "${MOUNT_POINT}" || { log "Failed to unmount ${MOUNT_POINT}."; exit 1; }
  231. # Manage UEFI boot entries
  232. manage_boot_entries
  233. log "Operation completed successfully."
  234. }
  235. # Execute the main function
  236. main "$@"