From ad8ef17942017ab0f8b5b602b72ae75e0de21f83 Mon Sep 17 00:00:00 2001 From: Andrew Battat Date: Wed, 29 Jan 2025 20:21:23 +0000 Subject: [PATCH 01/11] Refactor check-hardware.sh --- .../setupos-scripts/check-hardware.sh | 129 ++++++++++++------ 1 file changed, 90 insertions(+), 39 deletions(-) diff --git a/ic-os/components/setupos-scripts/check-hardware.sh b/ic-os/components/setupos-scripts/check-hardware.sh index 67261c63216..b4079d54168 100644 --- a/ic-os/components/setupos-scripts/check-hardware.sh +++ b/ic-os/components/setupos-scripts/check-hardware.sh @@ -1,5 +1,9 @@ #!/usr/bin/env bash +############################################################################### +# Environment & Script Setup +############################################################################### + set -o nounset set -o pipefail @@ -10,6 +14,10 @@ source /opt/ic/bin/functions.sh GENERATION= +############################################################################### +# Hardware Requirements +############################################################################### + MINIMUM_CPU_SOCKETS=2 GEN1_CPU_MODEL="AMD EPYC 7302" @@ -32,21 +40,36 @@ GEN2_MINIMUM_AGGREGATE_DISK_SIZE=32000000000000 GEN1_MINIMUM_DISK_SIZE=3200000000000 GEN1_MINIMUM_AGGREGATE_DISK_SIZE=32000000000000 -function check_generation() { - echo "* Checking Generation..." +############################################################################### +# Helper / Utility Functions +############################################################################### +function get_cpu_info_json() { local cpu="$(lshw -quiet -class cpu -json)" log_and_halt_installation_on_error "${?}" "Unable to fetch CPU information." + echo "${cpu}" +} + +############################################################################### +# Generation Detection +############################################################################### - for i in $(echo "${cpu}" | jq -r '.[].id'); do +function check_generation() { + echo "* Checking Generation..." + + local cpu_json="$(get_cpu_info_json)" + + # Loop over each CPU socket to detect its generation (1 or 2). + for i in $(echo "${cpu_json}" | jq -r '.[].id'); do if [[ ${i} =~ .*:.* ]]; then - unit=$(echo ${i} | awk -F ':' '{ print $2 }') + unit=$(echo "${i}" | awk -F ':' '{ print $2 }') else - unit=${i} + unit="${i}" fi + echo "* Checking CPU socket ${unit}..." + local model=$(echo "${cpu_json}" | jq -r --arg socket "${i}" '.[] | select(.id==$socket) | .product') - local model=$(echo "${cpu}" | jq -r --arg socket "${i}" '.[] | select(.id==$socket) | .product') if [[ ${model} =~ .*${GEN1_CPU_MODEL}.* ]]; then if [[ ${GENERATION} =~ ^(|1)$ ]]; then GENERATION=1 @@ -63,34 +86,38 @@ function check_generation() { log_and_halt_installation_on_error "2" " CPU Model does NOT meet system requirements." fi done - echo "* Generation" ${GENERATION} "detected" + + echo "* Generation ${GENERATION} detected" } +############################################################################### +# CPU Verification +############################################################################### + function check_num_cpus() { local num_cpu_sockets=$(lscpu | grep "Socket(s)" | awk '{print $2}') - if [ ${num_cpu_sockets} -ne ${MINIMUM_CPU_SOCKETS} ]; then + if [ "${num_cpu_sockets}" -ne "${MINIMUM_CPU_SOCKETS}" ]; then log_and_halt_installation_on_error "1" "Number of CPU's (${num_cpu_sockets}) does NOT meet system requirements (${MINIMUM_CPU_SOCKETS})." fi } function verify_gen1_cpu() { - local cpu="$(lshw -quiet -class cpu -json)" - log_and_halt_installation_on_error "${?}" "Unable to fetch CPU information." + local cpu_json="$(get_cpu_info_json)" - local sockets=$(echo "${cpu}" | jq -r '.[].id' | wc -l) + local sockets=$(echo "${cpu_json}" | jq -r '.[].id' | wc -l) log_and_halt_installation_on_error "${?}" "Unable to extract CPU sockets." - if [ ${sockets} -eq ${GEN1_CPU_SOCKETS} ]; then + if [ "${sockets}" -eq "${GEN1_CPU_SOCKETS}" ]; then echo " Number of sockets (${sockets}/${GEN1_CPU_SOCKETS}) meets system requirements." else log_and_halt_installation_on_error "1" " Number of sockets (${sockets}/${GEN1_CPU_SOCKETS}) does NOT meet system requirements." fi - for i in $(echo "${cpu}" | jq -r '.[].id'); do - unit=$(echo ${i} | awk -F ':' '{ print $2 }') + for i in $(echo "${cpu_json}" | jq -r '.[].id'); do + local unit=$(echo "${i}" | awk -F ':' '{ print $2 }') echo "* Verifying CPU socket ${unit}..." - local model=$(echo "${cpu}" | jq -r --arg socket "${i}" '.[] | select(.id==$socket) | .product') + local model=$(echo "${cpu_json}" | jq -r --arg socket "${i}" '.[] | select(.id==$socket) | .product') if [[ ${model} =~ .*${GEN1_CPU_MODEL}.* ]]; then echo " Model meets system requirements." else @@ -99,7 +126,10 @@ function verify_gen1_cpu() { echo "* Verifying CPU capabilities..." for c in "${GEN1_CPU_CAPABILITIES[@]}"; do - local capability=$(echo "${cpu}" | jq -r --arg socket "${i}" --arg capability "${c}" '.[] | select(.id==$socket) | .capabilities[$capability]') + local capability=$(echo "${cpu_json}" | jq -r \ + --arg socket "${i}" \ + --arg capability "${c}" \ + '.[] | select(.id==$socket) | .capabilities[$capability]') log_and_halt_installation_on_error "$?" "Capability '${c}' does NOT meet system requirements.." if [[ ${capability} =~ .*true.* ]]; then @@ -110,7 +140,7 @@ function verify_gen1_cpu() { done local num_threads=$(nproc) - if [ ${num_threads} -eq ${GEN1_CPU_THREADS} ]; then + if [ "${num_threads}" -eq "${GEN1_CPU_THREADS}" ]; then echo " Number of threads (${num_threads}/${GEN1_CPU_THREADS}) meets system requirements." else log_and_halt_installation_on_error "1" "Number of threads (${num_threads}/${GEN1_CPU_THREADS}) does NOT meet system requirements." @@ -119,16 +149,15 @@ function verify_gen1_cpu() { } function verify_gen2_cpu() { - local cpu="$(lshw -quiet -class cpu -json)" - log_and_halt_installation_on_error "${?}" "Unable to fetch CPU information." + local cpu_json="$(get_cpu_info_json)" check_num_cpus - for i in $(echo "${cpu}" | jq -r '.[].id'); do - unit=$(echo ${i} | awk -F ':' '{ print $2 }') + for i in $(echo "${cpu_json}" | jq -r '.[].id'); do + local unit=$(echo "${i}" | awk -F ':' '{ print $2 }') echo "* Verifying CPU socket ${unit}..." - local model=$(echo "${cpu}" | jq -r --arg socket "${i}" '.[] | select(.id==$socket) | .product') + local model=$(echo "${cpu_json}" | jq -r --arg socket "${i}" '.[] | select(.id==$socket) | .product') if [[ ${model} =~ .*${GEN2_CPU_MODEL}.* ]]; then echo " Model meets system requirements." else @@ -137,7 +166,10 @@ function verify_gen2_cpu() { echo "* Verifying CPU capabilities..." for c in "${GEN2_CPU_CAPABILITIES[@]}"; do - local capability=$(echo "${cpu}" | jq -r --arg socket "${i}" --arg capability "${c}" '.[] | select(.id==$socket) | .capabilities[$capability]') + local capability=$(echo "${cpu_json}" | jq -r \ + --arg socket "${i}" \ + --arg capability "${c}" \ + '.[] | select(.id==$socket) | .capabilities[$capability]') log_and_halt_installation_on_error "$?" "Capability '${c}' does NOT meet system requirements.." if [[ ${capability} =~ .*true.* ]]; then @@ -149,27 +181,32 @@ function verify_gen2_cpu() { done local num_threads=$(nproc) - if [ ${num_threads} -lt ${GEN2_MINIMUM_CPU_THREADS} ]; then + if [ "${num_threads}" -lt "${GEN2_MINIMUM_CPU_THREADS}" ]; then log_and_halt_installation_on_error "1" "Number of threads (${num_threads}) does NOT meet system requirements (${GEN2_MINIMUM_CPU_THREADS})" fi } function verify_cpu() { - echo "* Verifying Generation" ${GENERATION} "CPU..." - if [[ ${GENERATION} == 1 ]]; then + echo "* Verifying Generation ${GENERATION} CPU..." + + if [[ "${GENERATION}" == "1" ]]; then verify_gen1_cpu else verify_gen2_cpu fi } +############################################################################### +# Memory Verification +############################################################################### + function verify_memory() { echo "* Verifying system memory..." local memory="$(lshw -quiet -class memory -json)" log_and_halt_installation_on_error "${?}" "Unable to fetch memory information." - local size=$(echo ${memory} | jq -r '.[] | select(.id=="memory") | .size') + local size=$(echo "${memory}" | jq -r '.[] | select(.id=="memory") | .size') log_and_halt_installation_on_error "${?}" "Unable to extract memory size." if [ "${size}" -gt "${MINIMUM_MEMORY_SIZE}" ]; then @@ -179,17 +216,23 @@ function verify_memory() { fi } +############################################################################### +# Disk Verification +############################################################################### + function verify_gen1_disks() { - aggregate_size=0 - large_drives=($(get_large_drives)) - for drive in $(echo "${large_drives[@]}"); do + local aggregate_size=0 + local large_drives=($(get_large_drives)) + for drive in "${large_drives[@]}"; do test -b "/dev/${drive}" log_and_halt_installation_on_error "${?}" "Drive '/dev/${drive}' not found. Are all drives correctly installed?" local disk="$(lsblk --bytes --json /dev/${drive})" log_and_halt_installation_on_error "${?}" "Unable to fetch disk information." - local disk_size=$(echo ${disk} | jq -r --arg logicalname "${drive}" '.[][] | select(.name==$logicalname) | .size') + local disk_size=$(echo "${disk}" | jq -r \ + --arg logicalname "${drive}" \ + '.[][] | select(.name==$logicalname) | .size') log_and_halt_installation_on_error "${?}" "Unable to extract disk size." if [ "${disk_size}" -gt "${GEN1_MINIMUM_DISK_SIZE}" ]; then @@ -207,10 +250,9 @@ function verify_gen1_disks() { } function verify_gen2_disks() { - aggregate_size=0 - large_drives=($(get_large_drives)) - for drive in $(echo "${large_drives[@]}"); do - + local aggregate_size=0 + local large_drives=($(get_large_drives)) + for drive in "${large_drives[@]}"; do echo "* Verifying disk ${drive}" test -b "/dev/${drive}" @@ -219,7 +261,9 @@ function verify_gen2_disks() { local disk="$(lsblk --bytes --json /dev/${drive})" log_and_halt_installation_on_error "${?}" "Unable to fetch disk information." - local disk_size=$(echo ${disk} | jq -r --arg logicalname "${drive}" '.[][] | select(.name==$logicalname) | .size') + local disk_size=$(echo "${disk}" | jq -r \ + --arg logicalname "${drive}" \ + '.[][] | select(.name==$logicalname) | .size') log_and_halt_installation_on_error "${?}" "Unable to extract disk size." if [ "${disk_size}" -gt "${GEN2_MINIMUM_DISK_SIZE}" ]; then @@ -238,17 +282,21 @@ function verify_gen2_disks() { function verify_disks() { echo "* Verifying disks..." - if [[ ${GENERATION} == 1 ]]; then + if [[ "${GENERATION}" == "1" ]]; then verify_gen1_disks else verify_gen2_disks fi } +############################################################################### +# Deployment Path Verification +############################################################################### + function verify_deployment_path() { echo "* Verifying deployment path..." - if [[ ${GENERATION} == 2 ]] && [[ ! -f "${CONFIG_DIR}/node_operator_private_key.pem" ]]; then + if [[ "${GENERATION}" == "2" ]] && [[ ! -f "/boot/config/node_operator_private_key.pem" ]]; then echo -e "\n\n\n\n\n\n" echo -e "\033[1;31mWARNING: Gen2 hardware detected but no Node Operator Private Key found.\033[0m" echo -e "\033[1;31mGen2 hardware should be deployed using the Gen2 Node Deployment method.\033[0m" @@ -260,7 +308,10 @@ function verify_deployment_path() { fi } -# Establish run order +############################################################################### +# Main +############################################################################### + main() { log_start "$(basename $0)" if kernel_cmdline_bool_default_true ic.setupos.check_hardware; then From 789a068c974ab90544bd46d77d8ffde9c20ce139 Mon Sep 17 00:00:00 2001 From: Andrew Battat Date: Wed, 29 Jan 2025 20:34:48 +0000 Subject: [PATCH 02/11] Rename HARDWARE_GENERATION and refactor check_num_cpus --- .../setupos-scripts/check-hardware.sh | 59 +++++++++---------- 1 file changed, 28 insertions(+), 31 deletions(-) diff --git a/ic-os/components/setupos-scripts/check-hardware.sh b/ic-os/components/setupos-scripts/check-hardware.sh index b4079d54168..7ddd729b660 100644 --- a/ic-os/components/setupos-scripts/check-hardware.sh +++ b/ic-os/components/setupos-scripts/check-hardware.sh @@ -12,14 +12,12 @@ PATH="/sbin:/bin:/usr/sbin:/usr/bin" source /opt/ic/bin/functions.sh -GENERATION= +HARDWARE_GENERATION= ############################################################################### # Hardware Requirements ############################################################################### -MINIMUM_CPU_SOCKETS=2 - GEN1_CPU_MODEL="AMD EPYC 7302" GEN1_CPU_CAPABILITIES=("sev") GEN1_CPU_SOCKETS=2 @@ -27,6 +25,7 @@ GEN1_CPU_THREADS=64 GEN2_CPU_MODEL="AMD EPYC 7..3" GEN2_CPU_CAPABILITIES=("sev_snp") +GEN2_MINIMUM_CPU_SOCKETS=2 GEN2_MINIMUM_CPU_THREADS=64 # 510 GiB (Gibibyte) @@ -51,11 +50,11 @@ function get_cpu_info_json() { } ############################################################################### -# Generation Detection +# Hardware Generation Detection ############################################################################### -function check_generation() { - echo "* Checking Generation..." +function check_hardware_generation() { + echo "* Checking hardware generation..." local cpu_json="$(get_cpu_info_json)" @@ -71,23 +70,23 @@ function check_generation() { local model=$(echo "${cpu_json}" | jq -r --arg socket "${i}" '.[] | select(.id==$socket) | .product') if [[ ${model} =~ .*${GEN1_CPU_MODEL}.* ]]; then - if [[ ${GENERATION} =~ ^(|1)$ ]]; then - GENERATION=1 + if [[ ${HARDWARE_GENERATION} =~ ^(|1)$ ]]; then + HARDWARE_GENERATION=1 else - log_and_halt_installation_on_error "1" " CPU Socket Generations inconsistent." + log_and_halt_installation_on_error "1" " CPU Socket Hardware Generations inconsistent." fi elif [[ ${model} =~ .*${GEN2_CPU_MODEL}.* ]]; then - if [[ ${GENERATION} =~ ^(|2)$ ]]; then - GENERATION=2 + if [[ ${HARDWARE_GENERATION} =~ ^(|2)$ ]]; then + HARDWARE_GENERATION=2 else - log_and_halt_installation_on_error "1" " CPU Socket Generations inconsistent." + log_and_halt_installation_on_error "1" " CPU Socket Hardware Generations inconsistent." fi else log_and_halt_installation_on_error "2" " CPU Model does NOT meet system requirements." fi done - echo "* Generation ${GENERATION} detected" + echo "* Hardware generation ${HARDWARE_GENERATION} detected" } ############################################################################### @@ -95,23 +94,21 @@ function check_generation() { ############################################################################### function check_num_cpus() { - local num_cpu_sockets=$(lscpu | grep "Socket(s)" | awk '{print $2}') - if [ "${num_cpu_sockets}" -ne "${MINIMUM_CPU_SOCKETS}" ]; then - log_and_halt_installation_on_error "1" "Number of CPU's (${num_cpu_sockets}) does NOT meet system requirements (${MINIMUM_CPU_SOCKETS})." + local required_sockets="$1" + + local cpu_json="$(get_cpu_info_json)" + local num_cpu_sockets=$(echo "${cpu_json}" | jq -r '.[].id' | wc -l) + log_and_halt_installation_on_error "$?" "Unable to extract CPU sockets from CPU JSON." + + if [ "${num_cpu_sockets}" -ne "${required_sockets}" ]; then + log_and_halt_installation_on_error "1" "Number of CPU sockets (${num_cpu_sockets}) does NOT meet system requirements (expected ${required_sockets})." fi } function verify_gen1_cpu() { local cpu_json="$(get_cpu_info_json)" - local sockets=$(echo "${cpu_json}" | jq -r '.[].id' | wc -l) - log_and_halt_installation_on_error "${?}" "Unable to extract CPU sockets." - - if [ "${sockets}" -eq "${GEN1_CPU_SOCKETS}" ]; then - echo " Number of sockets (${sockets}/${GEN1_CPU_SOCKETS}) meets system requirements." - else - log_and_halt_installation_on_error "1" " Number of sockets (${sockets}/${GEN1_CPU_SOCKETS}) does NOT meet system requirements." - fi + check_num_cpus "${GEN1_CPU_SOCKETS}" for i in $(echo "${cpu_json}" | jq -r '.[].id'); do local unit=$(echo "${i}" | awk -F ':' '{ print $2 }') @@ -151,7 +148,7 @@ function verify_gen1_cpu() { function verify_gen2_cpu() { local cpu_json="$(get_cpu_info_json)" - check_num_cpus + check_num_cpus "${GEN2_MINIMUM_CPU_SOCKETS}" for i in $(echo "${cpu_json}" | jq -r '.[].id'); do local unit=$(echo "${i}" | awk -F ':' '{ print $2 }') @@ -187,9 +184,9 @@ function verify_gen2_cpu() { } function verify_cpu() { - echo "* Verifying Generation ${GENERATION} CPU..." + echo "* Verifying hardware generation ${HARDWARE_GENERATION} CPU..." - if [[ "${GENERATION}" == "1" ]]; then + if [[ "${HARDWARE_GENERATION}" == "1" ]]; then verify_gen1_cpu else verify_gen2_cpu @@ -282,7 +279,7 @@ function verify_gen2_disks() { function verify_disks() { echo "* Verifying disks..." - if [[ "${GENERATION}" == "1" ]]; then + if [[ "${HARDWARE_GENERATION}" == "1" ]]; then verify_gen1_disks else verify_gen2_disks @@ -296,7 +293,7 @@ function verify_disks() { function verify_deployment_path() { echo "* Verifying deployment path..." - if [[ "${GENERATION}" == "2" ]] && [[ ! -f "/boot/config/node_operator_private_key.pem" ]]; then + if [[ "${HARDWARE_GENERATION}" == "2" ]] && [[ ! -f "/boot/config/node_operator_private_key.pem" ]]; then echo -e "\n\n\n\n\n\n" echo -e "\033[1;31mWARNING: Gen2 hardware detected but no Node Operator Private Key found.\033[0m" echo -e "\033[1;31mGen2 hardware should be deployed using the Gen2 Node Deployment method.\033[0m" @@ -315,14 +312,14 @@ function verify_deployment_path() { main() { log_start "$(basename $0)" if kernel_cmdline_bool_default_true ic.setupos.check_hardware; then - check_generation + check_hardware_generation verify_cpu verify_memory verify_disks verify_deployment_path else echo "* Hardware checks skipped by request via kernel command line" - GENERATION=2 + HARDWARE_GENERATION=2 fi log_end "$(basename $0)" } From 3623f14fbf624d99f73b56c7d9e6c1e57a7aea1c Mon Sep 17 00:00:00 2001 From: Andrew Battat Date: Wed, 29 Jan 2025 21:01:56 +0000 Subject: [PATCH 03/11] Minor touch ups --- .../setupos-scripts/check-hardware.sh | 40 ++++++++++--------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/ic-os/components/setupos-scripts/check-hardware.sh b/ic-os/components/setupos-scripts/check-hardware.sh index 7ddd729b660..d50661fd314 100644 --- a/ic-os/components/setupos-scripts/check-hardware.sh +++ b/ic-os/components/setupos-scripts/check-hardware.sh @@ -40,21 +40,21 @@ GEN1_MINIMUM_DISK_SIZE=3200000000000 GEN1_MINIMUM_AGGREGATE_DISK_SIZE=32000000000000 ############################################################################### -# Helper / Utility Functions +# Helper Functions ############################################################################### function get_cpu_info_json() { - local cpu="$(lshw -quiet -class cpu -json)" + local cpu_json="$(lshw -quiet -class cpu -json)" log_and_halt_installation_on_error "${?}" "Unable to fetch CPU information." - echo "${cpu}" + echo "${cpu_json}" } ############################################################################### # Hardware Generation Detection ############################################################################### -function check_hardware_generation() { - echo "* Checking hardware generation..." +function detect_hardware_generation() { + echo "* Detecting hardware generation..." local cpu_json="$(get_cpu_info_json)" @@ -73,16 +73,16 @@ function check_hardware_generation() { if [[ ${HARDWARE_GENERATION} =~ ^(|1)$ ]]; then HARDWARE_GENERATION=1 else - log_and_halt_installation_on_error "1" " CPU Socket Hardware Generations inconsistent." + log_and_halt_installation_on_error "1" "CPU Socket Hardware Generations inconsistent." fi elif [[ ${model} =~ .*${GEN2_CPU_MODEL}.* ]]; then if [[ ${HARDWARE_GENERATION} =~ ^(|2)$ ]]; then HARDWARE_GENERATION=2 else - log_and_halt_installation_on_error "1" " CPU Socket Hardware Generations inconsistent." + log_and_halt_installation_on_error "1" "CPU Socket Hardware Generations inconsistent." fi else - log_and_halt_installation_on_error "2" " CPU Model does NOT meet system requirements." + log_and_halt_installation_on_error "2" "CPU Model does NOT meet system requirements." fi done @@ -116,7 +116,7 @@ function verify_gen1_cpu() { local model=$(echo "${cpu_json}" | jq -r --arg socket "${i}" '.[] | select(.id==$socket) | .product') if [[ ${model} =~ .*${GEN1_CPU_MODEL}.* ]]; then - echo " Model meets system requirements." + echo "Model meets system requirements." else log_and_halt_installation_on_error "1" "Model does NOT meet system requirements.." fi @@ -130,7 +130,7 @@ function verify_gen1_cpu() { log_and_halt_installation_on_error "$?" "Capability '${c}' does NOT meet system requirements.." if [[ ${capability} =~ .*true.* ]]; then - echo " Capability '${c}' meets system requirements." + echo "Capability '${c}' meets system requirements." else log_and_halt_installation_on_error "$?" "Capability '${c}' does NOT meet system requirements.." fi @@ -138,7 +138,7 @@ function verify_gen1_cpu() { local num_threads=$(nproc) if [ "${num_threads}" -eq "${GEN1_CPU_THREADS}" ]; then - echo " Number of threads (${num_threads}/${GEN1_CPU_THREADS}) meets system requirements." + echo "Number of threads (${num_threads}/${GEN1_CPU_THREADS}) meets system requirements." else log_and_halt_installation_on_error "1" "Number of threads (${num_threads}/${GEN1_CPU_THREADS}) does NOT meet system requirements." fi @@ -156,7 +156,7 @@ function verify_gen2_cpu() { local model=$(echo "${cpu_json}" | jq -r --arg socket "${i}" '.[] | select(.id==$socket) | .product') if [[ ${model} =~ .*${GEN2_CPU_MODEL}.* ]]; then - echo " Model meets system requirements." + echo "Model meets system requirements." else log_and_halt_installation_on_error "1" "Model does NOT meet system requirements.." fi @@ -170,7 +170,7 @@ function verify_gen2_cpu() { log_and_halt_installation_on_error "$?" "Capability '${c}' does NOT meet system requirements.." if [[ ${capability} =~ .*true.* ]]; then - echo " Capability '${c}' meets system requirements." + echo "Capability '${c}' meets system requirements." else log_and_halt_installation_on_error "$?" "Capability '${c}' does NOT meet system requirements.." fi @@ -207,7 +207,7 @@ function verify_memory() { log_and_halt_installation_on_error "${?}" "Unable to extract memory size." if [ "${size}" -gt "${MINIMUM_MEMORY_SIZE}" ]; then - echo " Memory size (${size} bytes) meets system requirements." + echo "Memory size (${size} bytes) meets system requirements." else log_and_halt_installation_on_error "1" "Memory size (${size} bytes/${MINIMUM_MEMORY_SIZE}) does NOT meet system requirements." fi @@ -221,6 +221,8 @@ function verify_gen1_disks() { local aggregate_size=0 local large_drives=($(get_large_drives)) for drive in "${large_drives[@]}"; do + echo "* Verifying disk ${drive}" + test -b "/dev/${drive}" log_and_halt_installation_on_error "${?}" "Drive '/dev/${drive}' not found. Are all drives correctly installed?" @@ -233,14 +235,14 @@ function verify_gen1_disks() { log_and_halt_installation_on_error "${?}" "Unable to extract disk size." if [ "${disk_size}" -gt "${GEN1_MINIMUM_DISK_SIZE}" ]; then - echo " Disk size (${disk_size} bytes) meets system requirements." + echo "Disk size (${disk_size} bytes) meets system requirements." else log_and_halt_installation_on_error "1" "Disk size (${disk_size} bytes/${GEN1_MINIMUM_DISK_SIZE}) does NOT meet system requirements." fi aggregate_size=$((aggregate_size + disk_size)) done if [ "${aggregate_size}" -gt "${GEN1_MINIMUM_AGGREGATE_DISK_SIZE}" ]; then - echo " Aggregate Disk size (${aggregate_size} bytes) meets system requirements." + echo "Aggregate Disk size (${aggregate_size} bytes) meets system requirements." else log_and_halt_installation_on_error "1" "Aggregate Disk size (${aggregate_size} bytes/${GEN1_MINIMUM_AGGREGATE_DISK_SIZE}) does NOT meet system requirements." fi @@ -264,14 +266,14 @@ function verify_gen2_disks() { log_and_halt_installation_on_error "${?}" "Unable to extract disk size." if [ "${disk_size}" -gt "${GEN2_MINIMUM_DISK_SIZE}" ]; then - echo " Disk size (${disk_size} bytes) meets system requirements." + echo "Disk size (${disk_size} bytes) meets system requirements." else log_and_halt_installation_on_error "1" "Disk size (${disk_size} bytes/${GEN2_MINIMUM_DISK_SIZE}) does NOT meet system requirements." fi aggregate_size=$((aggregate_size + disk_size)) done if [ "${aggregate_size}" -gt "${GEN2_MINIMUM_AGGREGATE_DISK_SIZE}" ]; then - echo " Aggregate Disk size (${aggregate_size} bytes) meets system requirements." + echo "Aggregate Disk size (${aggregate_size} bytes) meets system requirements." else log_and_halt_installation_on_error "1" "Aggregate Disk size (${aggregate_size} bytes/${GEN2_MINIMUM_AGGREGATE_DISK_SIZE}) does NOT meet system requirements." fi @@ -312,7 +314,7 @@ function verify_deployment_path() { main() { log_start "$(basename $0)" if kernel_cmdline_bool_default_true ic.setupos.check_hardware; then - check_hardware_generation + detect_hardware_generation verify_cpu verify_memory verify_disks From 189713d6b7f570b67f714fe3e0cf41fd6cddd4c5 Mon Sep 17 00:00:00 2001 From: Andrew Battat Date: Wed, 29 Jan 2025 21:06:01 +0000 Subject: [PATCH 04/11] verify_disks code reuse --- .../setupos-scripts/check-hardware.sh | 49 +++++-------------- 1 file changed, 12 insertions(+), 37 deletions(-) diff --git a/ic-os/components/setupos-scripts/check-hardware.sh b/ic-os/components/setupos-scripts/check-hardware.sh index d50661fd314..c6631d8c6a5 100644 --- a/ic-os/components/setupos-scripts/check-hardware.sh +++ b/ic-os/components/setupos-scripts/check-hardware.sh @@ -217,40 +217,12 @@ function verify_memory() { # Disk Verification ############################################################################### -function verify_gen1_disks() { +function verify_disks_helper() { + local min_disk_size="${1}" + local min_aggregate_disk_size="${2}" local aggregate_size=0 local large_drives=($(get_large_drives)) - for drive in "${large_drives[@]}"; do - echo "* Verifying disk ${drive}" - - test -b "/dev/${drive}" - log_and_halt_installation_on_error "${?}" "Drive '/dev/${drive}' not found. Are all drives correctly installed?" - - local disk="$(lsblk --bytes --json /dev/${drive})" - log_and_halt_installation_on_error "${?}" "Unable to fetch disk information." - - local disk_size=$(echo "${disk}" | jq -r \ - --arg logicalname "${drive}" \ - '.[][] | select(.name==$logicalname) | .size') - log_and_halt_installation_on_error "${?}" "Unable to extract disk size." - - if [ "${disk_size}" -gt "${GEN1_MINIMUM_DISK_SIZE}" ]; then - echo "Disk size (${disk_size} bytes) meets system requirements." - else - log_and_halt_installation_on_error "1" "Disk size (${disk_size} bytes/${GEN1_MINIMUM_DISK_SIZE}) does NOT meet system requirements." - fi - aggregate_size=$((aggregate_size + disk_size)) - done - if [ "${aggregate_size}" -gt "${GEN1_MINIMUM_AGGREGATE_DISK_SIZE}" ]; then - echo "Aggregate Disk size (${aggregate_size} bytes) meets system requirements." - else - log_and_halt_installation_on_error "1" "Aggregate Disk size (${aggregate_size} bytes/${GEN1_MINIMUM_AGGREGATE_DISK_SIZE}) does NOT meet system requirements." - fi -} -function verify_gen2_disks() { - local aggregate_size=0 - local large_drives=($(get_large_drives)) for drive in "${large_drives[@]}"; do echo "* Verifying disk ${drive}" @@ -265,26 +237,29 @@ function verify_gen2_disks() { '.[][] | select(.name==$logicalname) | .size') log_and_halt_installation_on_error "${?}" "Unable to extract disk size." - if [ "${disk_size}" -gt "${GEN2_MINIMUM_DISK_SIZE}" ]; then + if [ "${disk_size}" -gt "${min_disk_size}" ]; then echo "Disk size (${disk_size} bytes) meets system requirements." else - log_and_halt_installation_on_error "1" "Disk size (${disk_size} bytes/${GEN2_MINIMUM_DISK_SIZE}) does NOT meet system requirements." + log_and_halt_installation_on_error "1" "Disk size (${disk_size} bytes/${min_disk_size}) does NOT meet system requirements." fi + aggregate_size=$((aggregate_size + disk_size)) done - if [ "${aggregate_size}" -gt "${GEN2_MINIMUM_AGGREGATE_DISK_SIZE}" ]; then + + if [ "${aggregate_size}" -gt "${min_aggregate_disk_size}" ]; then echo "Aggregate Disk size (${aggregate_size} bytes) meets system requirements." else - log_and_halt_installation_on_error "1" "Aggregate Disk size (${aggregate_size} bytes/${GEN2_MINIMUM_AGGREGATE_DISK_SIZE}) does NOT meet system requirements." + log_and_halt_installation_on_error "1" "Aggregate Disk size (${aggregate_size} bytes/${min_aggregate_disk_size}) does NOT meet system requirements." fi } + function verify_disks() { echo "* Verifying disks..." if [[ "${HARDWARE_GENERATION}" == "1" ]]; then - verify_gen1_disks + verify_disks_helper "${GEN1_MINIMUM_DISK_SIZE}" "${GEN1_MINIMUM_AGGREGATE_DISK_SIZE}" else - verify_gen2_disks + verify_disks_helper "${GEN2_MINIMUM_DISK_SIZE}" "${GEN2_MINIMUM_AGGREGATE_DISK_SIZE}" fi } From 2f7d446857352e74f863175073a3ce6cc01a7787 Mon Sep 17 00:00:00 2001 From: Andrew Battat Date: Wed, 29 Jan 2025 21:22:01 +0000 Subject: [PATCH 05/11] Reduce cpu verification code repeat --- .../setupos-scripts/check-hardware.sh | 91 +++++++++---------- 1 file changed, 41 insertions(+), 50 deletions(-) diff --git a/ic-os/components/setupos-scripts/check-hardware.sh b/ic-os/components/setupos-scripts/check-hardware.sh index c6631d8c6a5..2f87ed1b9f2 100644 --- a/ic-os/components/setupos-scripts/check-hardware.sh +++ b/ic-os/components/setupos-scripts/check-hardware.sh @@ -94,92 +94,83 @@ function detect_hardware_generation() { ############################################################################### function check_num_cpus() { - local required_sockets="$1" + local cpu_json="$1" + local required_sockets="$2" - local cpu_json="$(get_cpu_info_json)" local num_cpu_sockets=$(echo "${cpu_json}" | jq -r '.[].id' | wc -l) log_and_halt_installation_on_error "$?" "Unable to extract CPU sockets from CPU JSON." - if [ "${num_cpu_sockets}" -ne "${required_sockets}" ]; then + if [ "${num_cpu_sockets}" -lt "${required_sockets}" ]; then log_and_halt_installation_on_error "1" "Number of CPU sockets (${num_cpu_sockets}) does NOT meet system requirements (expected ${required_sockets})." fi } -function verify_gen1_cpu() { - local cpu_json="$(get_cpu_info_json)" +# Verifies that all CPU sockets match a required model pattern and have certain capabilities. +function verify_model_and_capabilities_for_all_sockets() { + local cpu_json="$1" + local required_model="$2" + shift 2 + local required_capabilities=("$@") - check_num_cpus "${GEN1_CPU_SOCKETS}" + for socket_id in $(echo "${cpu_json}" | jq -r '.[].id'); do + local unit=$(echo "${socket_id}" | awk -F ':' '{ print $2 }') - for i in $(echo "${cpu_json}" | jq -r '.[].id'); do - local unit=$(echo "${i}" | awk -F ':' '{ print $2 }') echo "* Verifying CPU socket ${unit}..." - - local model=$(echo "${cpu_json}" | jq -r --arg socket "${i}" '.[] | select(.id==$socket) | .product') - if [[ ${model} =~ .*${GEN1_CPU_MODEL}.* ]]; then + local model=$(echo "${cpu_json}" | jq -r --arg socket "${socket_id}" '.[] | select(.id==$socket) | .product') + if [[ ${model} =~ .*${required_model}.* ]]; then echo "Model meets system requirements." else log_and_halt_installation_on_error "1" "Model does NOT meet system requirements.." fi echo "* Verifying CPU capabilities..." - for c in "${GEN1_CPU_CAPABILITIES[@]}"; do + for capability_name in "${required_capabilities[@]}"; do local capability=$(echo "${cpu_json}" | jq -r \ - --arg socket "${i}" \ - --arg capability "${c}" \ + --arg socket "${socket_id}" \ + --arg capability "${capability_name}" \ '.[] | select(.id==$socket) | .capabilities[$capability]') - log_and_halt_installation_on_error "$?" "Capability '${c}' does NOT meet system requirements.." + log_and_halt_installation_on_error "$?" "Capability '${capability_name}' does NOT meet system requirements.." if [[ ${capability} =~ .*true.* ]]; then - echo "Capability '${c}' meets system requirements." + echo "Capability '${capability_name}' meets system requirements." else - log_and_halt_installation_on_error "$?" "Capability '${c}' does NOT meet system requirements.." + log_and_halt_installation_on_error "$?" "Capability '${capability_name}' does NOT meet system requirements.." fi done - - local num_threads=$(nproc) - if [ "${num_threads}" -eq "${GEN1_CPU_THREADS}" ]; then - echo "Number of threads (${num_threads}/${GEN1_CPU_THREADS}) meets system requirements." - else - log_and_halt_installation_on_error "1" "Number of threads (${num_threads}/${GEN1_CPU_THREADS}) does NOT meet system requirements." - fi done } -function verify_gen2_cpu() { +function verify_gen1_cpu() { local cpu_json="$(get_cpu_info_json)" - check_num_cpus "${GEN2_MINIMUM_CPU_SOCKETS}" + check_num_cpus "${cpu_json}" "${GEN1_CPU_SOCKETS}" - for i in $(echo "${cpu_json}" | jq -r '.[].id'); do - local unit=$(echo "${i}" | awk -F ':' '{ print $2 }') - echo "* Verifying CPU socket ${unit}..." + verify_model_and_capabilities_for_all_sockets \ + "${cpu_json}" \ + "${GEN1_CPU_MODEL}" \ + "${GEN1_CPU_CAPABILITIES[@]}" - local model=$(echo "${cpu_json}" | jq -r --arg socket "${i}" '.[] | select(.id==$socket) | .product') - if [[ ${model} =~ .*${GEN2_CPU_MODEL}.* ]]; then - echo "Model meets system requirements." - else - log_and_halt_installation_on_error "1" "Model does NOT meet system requirements.." - fi + local num_threads=$(nproc) + if [ "${num_threads}" -eq "${GEN1_CPU_THREADS}" ]; then + echo "Number of threads (${num_threads}/${GEN1_CPU_THREADS}) meets system requirements." + else + log_and_halt_installation_on_error "1" "Number of threads (${num_threads}/${GEN1_CPU_THREADS}) does NOT meet system requirements." + fi +} - echo "* Verifying CPU capabilities..." - for c in "${GEN2_CPU_CAPABILITIES[@]}"; do - local capability=$(echo "${cpu_json}" | jq -r \ - --arg socket "${i}" \ - --arg capability "${c}" \ - '.[] | select(.id==$socket) | .capabilities[$capability]') - log_and_halt_installation_on_error "$?" "Capability '${c}' does NOT meet system requirements.." +function verify_gen2_cpu() { + local cpu_json="$(get_cpu_info_json)" - if [[ ${capability} =~ .*true.* ]]; then - echo "Capability '${c}' meets system requirements." - else - log_and_halt_installation_on_error "$?" "Capability '${c}' does NOT meet system requirements.." - fi - done - done + check_num_cpus "${cpu_json}" "${GEN2_MINIMUM_CPU_SOCKETS}" + + verify_model_and_capabilities_for_all_sockets \ + "${cpu_json}" \ + "${GEN2_CPU_MODEL}" \ + "${GEN2_CPU_CAPABILITIES[@]}" local num_threads=$(nproc) if [ "${num_threads}" -lt "${GEN2_MINIMUM_CPU_THREADS}" ]; then - log_and_halt_installation_on_error "1" "Number of threads (${num_threads}) does NOT meet system requirements (${GEN2_MINIMUM_CPU_THREADS})" + log_and_halt_installation_on_error "1" "Number of threads (${num_threads}) does NOT meet system requirements (${GEN2_MINIMUM_CPU_THREADS})." fi } From b7726a1efbc76a6840515f748cd4177224be0e90 Mon Sep 17 00:00:00 2001 From: Andrew Battat Date: Wed, 29 Jan 2025 21:24:23 +0000 Subject: [PATCH 06/11] Remove unnecessary HARDWARE_GENERATION declaration --- ic-os/components/setupos-scripts/check-hardware.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/ic-os/components/setupos-scripts/check-hardware.sh b/ic-os/components/setupos-scripts/check-hardware.sh index 2f87ed1b9f2..94af2c89391 100644 --- a/ic-os/components/setupos-scripts/check-hardware.sh +++ b/ic-os/components/setupos-scripts/check-hardware.sh @@ -287,7 +287,6 @@ main() { verify_deployment_path else echo "* Hardware checks skipped by request via kernel command line" - HARDWARE_GENERATION=2 fi log_end "$(basename $0)" } From 73403a90776f8c2a6cc8f5c35257ff893b813753 Mon Sep 17 00:00:00 2001 From: Andrew Battat Date: Wed, 29 Jan 2025 21:27:56 +0000 Subject: [PATCH 07/11] Rename socket_id in loop --- ic-os/components/setupos-scripts/check-hardware.sh | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/ic-os/components/setupos-scripts/check-hardware.sh b/ic-os/components/setupos-scripts/check-hardware.sh index 94af2c89391..e270cab5146 100644 --- a/ic-os/components/setupos-scripts/check-hardware.sh +++ b/ic-os/components/setupos-scripts/check-hardware.sh @@ -58,16 +58,15 @@ function detect_hardware_generation() { local cpu_json="$(get_cpu_info_json)" - # Loop over each CPU socket to detect its generation (1 or 2). - for i in $(echo "${cpu_json}" | jq -r '.[].id'); do - if [[ ${i} =~ .*:.* ]]; then - unit=$(echo "${i}" | awk -F ':' '{ print $2 }') + for socket_id in $(echo "${cpu_json}" | jq -r '.[].id'); do + if [[ ${socket_id} =~ .*:.* ]]; then + unit=$(echo "${socket_id}" | awk -F ':' '{ print $2 }') else - unit="${i}" + unit="${socket_id}" fi echo "* Checking CPU socket ${unit}..." - local model=$(echo "${cpu_json}" | jq -r --arg socket "${i}" '.[] | select(.id==$socket) | .product') + local model=$(echo "${cpu_json}" | jq -r --arg socket "${socket_id}" '.[] | select(.id==$socket) | .product') if [[ ${model} =~ .*${GEN1_CPU_MODEL}.* ]]; then if [[ ${HARDWARE_GENERATION} =~ ^(|1)$ ]]; then From 2bb209a2fa0bc1f3663e19177d3e2b132246f4fe Mon Sep 17 00:00:00 2001 From: Andrew Battat Date: Wed, 29 Jan 2025 21:42:06 +0000 Subject: [PATCH 08/11] Miscellaneous improvements --- ic-os/components/setupos-scripts/check-hardware.sh | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/ic-os/components/setupos-scripts/check-hardware.sh b/ic-os/components/setupos-scripts/check-hardware.sh index e270cab5146..f1f15eb9977 100644 --- a/ic-os/components/setupos-scripts/check-hardware.sh +++ b/ic-os/components/setupos-scripts/check-hardware.sh @@ -81,7 +81,7 @@ function detect_hardware_generation() { log_and_halt_installation_on_error "1" "CPU Socket Hardware Generations inconsistent." fi else - log_and_halt_installation_on_error "2" "CPU Model does NOT meet system requirements." + log_and_halt_installation_on_error "1" "CPU Model does NOT meet system requirements." fi done @@ -128,7 +128,7 @@ function verify_model_and_capabilities_for_all_sockets() { --arg socket "${socket_id}" \ --arg capability "${capability_name}" \ '.[] | select(.id==$socket) | .capabilities[$capability]') - log_and_halt_installation_on_error "$?" "Capability '${capability_name}' does NOT meet system requirements.." + log_and_halt_installation_on_error "$?" "Failed to query CPU capabilities" if [[ ${capability} =~ .*true.* ]]; then echo "Capability '${capability_name}' meets system requirements." @@ -196,7 +196,7 @@ function verify_memory() { local size=$(echo "${memory}" | jq -r '.[] | select(.id=="memory") | .size') log_and_halt_installation_on_error "${?}" "Unable to extract memory size." - if [ "${size}" -gt "${MINIMUM_MEMORY_SIZE}" ]; then + if [ "${size}" -ge "${MINIMUM_MEMORY_SIZE}" ]; then echo "Memory size (${size} bytes) meets system requirements." else log_and_halt_installation_on_error "1" "Memory size (${size} bytes/${MINIMUM_MEMORY_SIZE}) does NOT meet system requirements." @@ -227,7 +227,7 @@ function verify_disks_helper() { '.[][] | select(.name==$logicalname) | .size') log_and_halt_installation_on_error "${?}" "Unable to extract disk size." - if [ "${disk_size}" -gt "${min_disk_size}" ]; then + if [ "${disk_size}" -ge "${min_disk_size}" ]; then echo "Disk size (${disk_size} bytes) meets system requirements." else log_and_halt_installation_on_error "1" "Disk size (${disk_size} bytes/${min_disk_size}) does NOT meet system requirements." @@ -236,14 +236,13 @@ function verify_disks_helper() { aggregate_size=$((aggregate_size + disk_size)) done - if [ "${aggregate_size}" -gt "${min_aggregate_disk_size}" ]; then + if [ "${aggregate_size}" -ge "${min_aggregate_disk_size}" ]; then echo "Aggregate Disk size (${aggregate_size} bytes) meets system requirements." else log_and_halt_installation_on_error "1" "Aggregate Disk size (${aggregate_size} bytes/${min_aggregate_disk_size}) does NOT meet system requirements." fi } - function verify_disks() { echo "* Verifying disks..." if [[ "${HARDWARE_GENERATION}" == "1" ]]; then From 6be1005bfc14299cd4790674f1cc6096f4857f36 Mon Sep 17 00:00:00 2001 From: Andrew Battat Date: Wed, 29 Jan 2025 21:45:57 +0000 Subject: [PATCH 09/11] Remove unnecessary comment --- ic-os/components/setupos-scripts/check-hardware.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/ic-os/components/setupos-scripts/check-hardware.sh b/ic-os/components/setupos-scripts/check-hardware.sh index f1f15eb9977..2c9b11f7250 100644 --- a/ic-os/components/setupos-scripts/check-hardware.sh +++ b/ic-os/components/setupos-scripts/check-hardware.sh @@ -104,7 +104,6 @@ function check_num_cpus() { fi } -# Verifies that all CPU sockets match a required model pattern and have certain capabilities. function verify_model_and_capabilities_for_all_sockets() { local cpu_json="$1" local required_model="$2" From 6fad5a1e318aaa8c889350cf150416050a328b4b Mon Sep 17 00:00:00 2001 From: Andrew Battat Date: Wed, 29 Jan 2025 22:07:11 +0000 Subject: [PATCH 10/11] Fix node_operator_private_key path --- ic-os/components/setupos-scripts/check-hardware.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ic-os/components/setupos-scripts/check-hardware.sh b/ic-os/components/setupos-scripts/check-hardware.sh index 2c9b11f7250..dd2cf2daa33 100644 --- a/ic-os/components/setupos-scripts/check-hardware.sh +++ b/ic-os/components/setupos-scripts/check-hardware.sh @@ -258,7 +258,7 @@ function verify_disks() { function verify_deployment_path() { echo "* Verifying deployment path..." - if [[ "${HARDWARE_GENERATION}" == "2" ]] && [[ ! -f "/boot/config/node_operator_private_key.pem" ]]; then + if [[ "${HARDWARE_GENERATION}" == "2" ]] && [[ ! -f "/config/node_operator_private_key.pem" ]]; then echo -e "\n\n\n\n\n\n" echo -e "\033[1;31mWARNING: Gen2 hardware detected but no Node Operator Private Key found.\033[0m" echo -e "\033[1;31mGen2 hardware should be deployed using the Gen2 Node Deployment method.\033[0m" From 2aa73d9af56a0c48c0f6694e78fe0e206c8516be Mon Sep 17 00:00:00 2001 From: Andrew Battat Date: Mon, 3 Feb 2025 16:15:22 +0000 Subject: [PATCH 11/11] Fix hardware requirement organization and comments --- ic-os/components/setupos-scripts/check-hardware.sh | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/ic-os/components/setupos-scripts/check-hardware.sh b/ic-os/components/setupos-scripts/check-hardware.sh index dd2cf2daa33..c0d9f5f5f2c 100644 --- a/ic-os/components/setupos-scripts/check-hardware.sh +++ b/ic-os/components/setupos-scripts/check-hardware.sh @@ -22,22 +22,20 @@ GEN1_CPU_MODEL="AMD EPYC 7302" GEN1_CPU_CAPABILITIES=("sev") GEN1_CPU_SOCKETS=2 GEN1_CPU_THREADS=64 +# Gen1 Dell has 10 * 3.2TB drives and Gen1 SuperMicro has 5 * 6.4 TB drives = 32TB +GEN1_MINIMUM_DISK_SIZE=3200000000000 +GEN1_MINIMUM_AGGREGATE_DISK_SIZE=32000000000000 GEN2_CPU_MODEL="AMD EPYC 7..3" GEN2_CPU_CAPABILITIES=("sev_snp") GEN2_MINIMUM_CPU_SOCKETS=2 GEN2_MINIMUM_CPU_THREADS=64 - -# 510 GiB (Gibibyte) -MINIMUM_MEMORY_SIZE=547608330240 - # Gen2 has 5 * 6.4 TB drives = 32TB GEN2_MINIMUM_DISK_SIZE=6400000000000 GEN2_MINIMUM_AGGREGATE_DISK_SIZE=32000000000000 -# Dell 10 3.2TB and SuperMicro has 5 7.4 TB drives = 32TB -GEN1_MINIMUM_DISK_SIZE=3200000000000 -GEN1_MINIMUM_AGGREGATE_DISK_SIZE=32000000000000 +# All nodes have the same memory requirement: 512 GB +MINIMUM_MEMORY_SIZE=547608330240 ############################################################################### # Helper Functions