Public repo to distribute scripts and config's
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 

309 lignes
8.8 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. log "Retrieving current boot entries..."
  70. BOOT_ENTRIES_INFO=$(efibootmgr -v | grep -E "^Boot[0-9A-F]{4}")
  71. # Arrays to hold boot entry numbers
  72. NETBOOT_ENTRIES=()
  73. ENTRIES_TO_DELETE=()
  74. # Identify netboot entries and entries to delete
  75. while read -r LINE; do
  76. ENTRY_NUM=$(echo "$LINE" | awk '{print $1}' | sed 's/Boot//;s/\*//')
  77. ENTRY_DESC=$(echo "$LINE" | cut -d' ' -f2-)
  78. ENTRY_PATH=$(echo "$LINE" | awk -F'File' '{print $2}')
  79. # Check if the entry is a netboot entry (e.g., contains "PXE", "Network", or "IPv4"/"IPv6")
  80. if echo "$ENTRY_DESC" | grep -qiE "(PXE|Network|IPV4|IPV6)"; then
  81. NETBOOT_ENTRIES+=("$ENTRY_NUM")
  82. log "Identified netboot entry: Boot$ENTRY_NUM - $ENTRY_DESC"
  83. else
  84. ENTRIES_TO_DELETE+=("$ENTRY_NUM")
  85. log "Marking entry for deletion: Boot$ENTRY_NUM - $ENTRY_DESC"
  86. fi
  87. done <<<"$BOOT_ENTRIES_INFO"
  88. # Delete non-netboot entries
  89. if [ ${#ENTRIES_TO_DELETE[@]} -gt 0 ]; then
  90. log "Deleting non-netboot boot entries..."
  91. for ENTRY_NUM in "${ENTRIES_TO_DELETE[@]}"; do
  92. efibootmgr -b "$ENTRY_NUM" -B
  93. log "Deleted boot entry Boot$ENTRY_NUM"
  94. done
  95. else
  96. log "No non-netboot entries to delete."
  97. fi
  98. # Create a new boot entry pointing to BOOTX64.EFI on the first partition
  99. log "Creating new boot entry for /dev/${PARTPREFIX}1..."
  100. # Adjust the partition number if necessary
  101. ESP_PART_NUM=1
  102. efibootmgr -c -d /dev/${BLOCKDEV} -p $ESP_PART_NUM -L "Zero-OS" -l "\\EFI\\BOOT\\BOOTX64.EFI" || {
  103. log "Error: Failed to create new boot entry."
  104. exit 1
  105. }
  106. # Retrieve the new boot entry number
  107. NEW_BOOT_NUM=$(efibootmgr | grep "Zero-OS" | awk '{print $1}' | sed 's/\*//;s/Boot//')
  108. if [ -z "$NEW_BOOT_NUM" ]; then
  109. log "Error: Failed to retrieve new boot entry number."
  110. exit 1
  111. fi
  112. # Set the new boot order: netboot entries first, followed by the new boot entry
  113. log "Setting new BootOrder with netboot entries first..."
  114. BOOT_ORDER=""
  115. for ENTRY_NUM in "${NETBOOT_ENTRIES[@]}"; do
  116. BOOT_ORDER+="$ENTRY_NUM,"
  117. done
  118. BOOT_ORDER+="$NEW_BOOT_NUM"
  119. efibootmgr -o "$BOOT_ORDER" || {
  120. log "Error: Failed to set new BootOrder."
  121. exit 1
  122. }
  123. log "New BootOrder set successfully: $BOOT_ORDER"
  124. }
  125. # Main script execution
  126. main() {
  127. # Default values
  128. BLOCKDEV_SPECIFIED=""
  129. FARM="1234"
  130. ENVIRONMENT="prod"
  131. # Parse command-line arguments
  132. while [[ $# -gt 0 ]]; do
  133. case "$1" in
  134. -d | --device)
  135. shift
  136. if [ -z "$1" ]; then
  137. log "Error: '--device' requires a non-empty option argument."
  138. usage
  139. fi
  140. BLOCKDEV_SPECIFIED="$1"
  141. shift
  142. ;;
  143. -f | --farm)
  144. shift
  145. if [ -z "$1" ]; then
  146. log "Error: '--farm' requires a non-empty option argument."
  147. usage
  148. fi
  149. FARM="$1"
  150. shift
  151. ;;
  152. -e | --environment)
  153. shift
  154. if [ -z "$1" ]; then
  155. log "Error: '--environment' requires a non-empty option argument."
  156. usage
  157. fi
  158. ENVIRONMENT="$1"
  159. shift
  160. ;;
  161. -h | --help)
  162. usage
  163. ;;
  164. *)
  165. log "Error: Unknown option: $1"
  166. usage
  167. ;;
  168. esac
  169. done
  170. # Validate environment
  171. case "$ENVIRONMENT" in
  172. dev | qa | test | prod)
  173. log "Using environment: $ENVIRONMENT"
  174. ;;
  175. *)
  176. log "Error: Invalid environment '$ENVIRONMENT'. Valid options are 'dev', 'qa', 'test', 'prod'."
  177. exit 1
  178. ;;
  179. esac
  180. if [ -n "$BLOCKDEV_SPECIFIED" ]; then
  181. # Use the specified block device
  182. if [[ "$BLOCKDEV_SPECIFIED" != /dev/* ]]; then
  183. BLOCKDEV_SPECIFIED="/dev/$BLOCKDEV_SPECIFIED"
  184. fi
  185. if [ ! -b "$BLOCKDEV_SPECIFIED" ]; then
  186. log "Error: Specified device $BLOCKDEV_SPECIFIED does not exist or is not a block device."
  187. exit 1
  188. fi
  189. BLOCKDEV="${BLOCKDEV_SPECIFIED##*/}"
  190. log "Using specified block device: $BLOCKDEV_SPECIFIED"
  191. else
  192. # Find a suitable block device
  193. if ! find_blockdev; then
  194. log "Error: No suitable block device found."
  195. exit 1
  196. fi
  197. log "Selected block device: /dev/${BLOCKDEV}"
  198. fi
  199. # Confirm with the user before proceeding
  200. read -p "This will erase all data on /dev/${BLOCKDEV}. Are you sure you want to proceed? (yes/[no]): " CONFIRM
  201. if [ "$CONFIRM" != "yes" ]; then
  202. log "Operation cancelled by user."
  203. exit 0
  204. fi
  205. # Determine partition naming convention
  206. if [[ $BLOCKDEV =~ [0-9]$ ]]; then
  207. PARTPREFIX="${BLOCKDEV}p"
  208. else
  209. PARTPREFIX="${BLOCKDEV}"
  210. fi
  211. # Wipe filesystem signatures
  212. log "Wiping filesystem signatures on /dev/${BLOCKDEV}..."
  213. wipefs -a -f /dev/${BLOCKDEV} || {
  214. log "Failed to wipe filesystem signatures."
  215. exit 1
  216. }
  217. # Create GPT partition table
  218. log "Creating GPT partition table on /dev/${BLOCKDEV}..."
  219. parted -s /dev/${BLOCKDEV} mklabel gpt || {
  220. log "Failed to create GPT partition table."
  221. exit 1
  222. }
  223. # Create partitions
  224. log "Creating partitions on /dev/${BLOCKDEV}..."
  225. if ! parted -s /dev/${BLOCKDEV} "mkpart zosboot fat16 1MiB 100MiB set 1 esp on mkpart zoscache btrfs 100MiB 100%"; then
  226. log "Failed to create partitions."
  227. exit 1
  228. fi
  229. # Format partitions
  230. log "Formatting /dev/${PARTPREFIX}1 as FAT32..."
  231. if ! mkfs.vfat -F32 -nZOSPXE /dev/${PARTPREFIX}1; then
  232. log "Failed to format /dev/${PARTPREFIX}1 as FAT32."
  233. exit 1
  234. fi
  235. log "Formatting /dev/${PARTPREFIX}2 as BTRFS..."
  236. if ! mkfs.btrfs -f /dev/${PARTPREFIX}2 -LZOSCACHE; then
  237. log "Failed to format /dev/${PARTPREFIX}2 as BTRFS."
  238. exit 1
  239. fi
  240. # Mount and prepare directories
  241. MOUNT_POINT="zospxe"
  242. log "Creating and mounting directory ./${MOUNT_POINT}..."
  243. mkdir -p "${MOUNT_POINT}"
  244. if ! mount /dev/${PARTPREFIX}1 -t vfat "${MOUNT_POINT}"; then
  245. log "Failed to mount /dev/${PARTPREFIX}1 to ${MOUNT_POINT}."
  246. exit 1
  247. fi
  248. log "Creating directory structure in ${MOUNT_POINT}..."
  249. mkdir -p "${MOUNT_POINT}/efi/boot"
  250. # Download the required BOOTX64.EFI file
  251. # EFI_FILE_URL="https://bootstrap.grid.tf/uefi/${ENVIRONMENT}/${FARM}"
  252. EFI_FILE_URL="https://bootstrap.grid.tf/uefi/${ENVIRONMENT}/${FARM}/debug/zero-os-development-zos-v4-debug-7d2de62033.efi?version=v4"
  253. log "Downloading BOOTX64.EFI from ${EFI_FILE_URL}..."
  254. if ! wget -q "${EFI_FILE_URL}" -O "${MOUNT_POINT}/efi/boot/BOOTX64.EFI"; then
  255. log "Failed to download BOOTX64.EFI."
  256. exit 1
  257. fi
  258. log "Download successful."
  259. # Unmount the partition
  260. log "Unmounting ${MOUNT_POINT}..."
  261. umount -r "${MOUNT_POINT}" || {
  262. log "Failed to unmount ${MOUNT_POINT}."
  263. exit 1
  264. }
  265. # Manage UEFI boot entries
  266. manage_boot_entries
  267. log "Operation completed successfully."
  268. }
  269. # Execute the main function
  270. main "$@"