Public repo to distribute scripts and config's
Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.
 

308 řádky
8.6 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. log "Downloading BOOTX64.EFI from ${EFI_FILE_URL}..."
  253. if ! wget -q "${EFI_FILE_URL}" -O "${MOUNT_POINT}/efi/boot/BOOTX64.EFI"; then
  254. log "Failed to download BOOTX64.EFI."
  255. exit 1
  256. fi
  257. log "Download successful."
  258. # Unmount the partition
  259. log "Unmounting ${MOUNT_POINT}..."
  260. umount -r "${MOUNT_POINT}" || {
  261. log "Failed to unmount ${MOUNT_POINT}."
  262. exit 1
  263. }
  264. # Manage UEFI boot entries
  265. manage_boot_entries
  266. log "Operation completed successfully."
  267. }
  268. # Execute the main function
  269. main "$@"