Handle target_disk detection strings
For preseed installs with pvcbootstrapd, implement "detect" strings, which can be used instead of fixed block paths to determine the required disk from a fixed set of information available to a human provisioning the servers, or from Redfish. The basic idea is thus: 1. The user specifies some physical attributes of the disk, either manually in a detect string of the preseed configuration, or by a physical identifier that Redfish can identify. 2. Redfish takes this and either passes it, or crafts a detect string itself based on its storage information, which is then passed to the installer preseed as the target_disk value. 3. The installer uses the provided values along with the output of the "lsscsi" command to determine which block device to use for the system disk. This supersedes and enhances the original "model-based" detection with far greater reliability and the ability to specify specific indexes.
This commit is contained in:
parent
2af6b837d8
commit
cebd6f0de2
|
@ -211,18 +211,63 @@ seed_config() {
|
||||||
host_ipaddr=$( ip -br address show ${target_interface} | awk '{ print $3 }' | awk -F '/' '{ print $1 }' )
|
host_ipaddr=$( ip -br address show ${target_interface} | awk '{ print $3 }' | awk -F '/' '{ print $1 }' )
|
||||||
|
|
||||||
# Handle the target disk
|
# Handle the target disk
|
||||||
if [[ -n ${target_disk_path} ]]; then
|
case "${target_disk}" in
|
||||||
target_disk="$( realpath ${target_disk_path} )"
|
/dev/*)
|
||||||
else
|
# Get the real path of the block device (for /dev/disk/* symlink paths)
|
||||||
# Find the (first) disk with the given model
|
target_disk="$( realpath ${target_disk} )"
|
||||||
for disk in /dev/sd?; do
|
;;
|
||||||
disk_model="$( fdisk -l ${disk} | grep 'Disk model:' | sed 's/Disk model: //g' )"
|
detect:*)
|
||||||
if [[ ${disk_model} == ${target_disk_model} ]]; then
|
# Read the detect string into separate variables
|
||||||
target_disk="${disk}"
|
# A detect string is formated thusly:
|
||||||
break
|
# detect:<Controller-or-Vendor-Name>:<0-indexed-ID>:<Capacity-in-human-units>
|
||||||
fi
|
# For example:
|
||||||
done
|
# detect:INTEL:1:800GB
|
||||||
fi
|
# detect:DELLBOSS:0:240GB
|
||||||
|
# detect:PERC H330 Mini:0:200GB
|
||||||
|
IFS=: read detect b_name b_id b_size <<<"${target_disk}"
|
||||||
|
# Get the lsscsi output (exclude NVMe)
|
||||||
|
lsscsi_data_all="$( lsscsi -s -N )"
|
||||||
|
# Get the available sizes, and match to within +/- 2%
|
||||||
|
lsscsi_sizes=( $( awk '{ print $NF }' <<<"${lsscsi_data_all}" | sort | uniq ) )
|
||||||
|
# For each size...
|
||||||
|
for size in ${lsscsi_sizes[@]}; do
|
||||||
|
# Get whether we match +2% and -2% sizes to handle human -> real deltas
|
||||||
|
# The break below is pretty safe. I can think of no two classes of disks
|
||||||
|
# where the difference is within 2% of each other. Even the common
|
||||||
|
# 120GB -> 128GB and 240GB -> 256GB size deltas are well outside of 2%,
|
||||||
|
# so this should be safe in all cases. 1% would be narrower but has more
|
||||||
|
# chance of mis-identifying due to rounding, while 3% gets into more
|
||||||
|
# contentious differences, so 2% seems like the best option.
|
||||||
|
# We use Python for this due to BASH's problematic handling of floating-
|
||||||
|
# point numbers.
|
||||||
|
is_match="$(
|
||||||
|
python <<EOF
|
||||||
|
from re import sub
|
||||||
|
b_size = float(sub(r'\D','','${b_size}'))
|
||||||
|
t_size = float(sub(r'\D','','${size}'))
|
||||||
|
plustwopct = t_size * 1.02
|
||||||
|
minustwopct = t_size * 0.98
|
||||||
|
if b_size > minustwopct and b_size < plustwopct:
|
||||||
|
print("match")
|
||||||
|
EOF
|
||||||
|
)"
|
||||||
|
# If we do, this size is our actual block size, not what was specified
|
||||||
|
if [[ -n ${is_match} ]]; then
|
||||||
|
b_size=${size}
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
# Search for the b_name first
|
||||||
|
lsscsi_data_name="$( grep --color=none -Fiw "${b_name}" <<<"${lsscsi_data_all}" )"
|
||||||
|
# Search for the b_blocks second
|
||||||
|
lsscsi_data_name_size="$( grep --color=none -Fiw "${b_size}" <<<"${lsscsi_data_name}" )"
|
||||||
|
# Read the /dev/X results into an array
|
||||||
|
lsscsi_filtered=( $( awk '{ print $(NF-1) }' <<<"${lsscsi_data_name_size}" ) )
|
||||||
|
# Get the b_id-th entry
|
||||||
|
target_disk="${lsscsi_filtered[${b_id}]}"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
if [[ ! -b ${target_disk} ]]; then
|
if [[ ! -b ${target_disk} ]]; then
|
||||||
echo "Invalid disk or disk not found!"
|
echo "Invalid disk or disk not found!"
|
||||||
exit 1
|
exit 1
|
||||||
|
|
Loading…
Reference in New Issue