From b95cbb14b13c289cbdfacc96422f6c01a66adca5 Mon Sep 17 00:00:00 2001 From: Lucas Alvares Gomes Date: Mon, 15 Dec 2014 19:13:32 +0000 Subject: [PATCH] Ironic: Deploy ramdisk to find the right root device As part of the blueprint root-device-hints Ironic will pass some to the deploy ramdisk some hints about which disk device it should pick to be root device (the one where the image will be deployed on). Before the deploy ramdisk would pick the first device it finds, but as the machine could have more than one SATA, SCSI or IDE disk controllers the order in which their corresponding device nodes are added is arbitrary causing devices like /dev/sda and /dev/sdb switching around on each boot time. Plus, as people are adding support to build RAID arrays in Ironic we need a way to tell it to use the just created device to be the root device. The list of hints that could be passed to the deploy ramdisk so it finds the right disk is: * wwn (STRING): unique storage identifier * serial (STRING): disk serial number * model (STRING): device identifier * vendor (STRING): device vendor * size (INT): The size of the disk in GB If not hints are passed, the deploy ramdisk will continue to do what it did before to find the disk. Change-Id: I8425f593e1a610af5a3697988702603ff218f2de --- .../init.d/70-ironic-root-device | 115 ++++++++++++++++++ .../deploy-ironic/init.d/80-deploy-ironic | 22 ++-- 2 files changed, 129 insertions(+), 8 deletions(-) create mode 100644 elements/deploy-ironic/init.d/70-ironic-root-device diff --git a/elements/deploy-ironic/init.d/70-ironic-root-device b/elements/deploy-ironic/init.d/70-ironic-root-device new file mode 100644 index 00000000..d61b9a3e --- /dev/null +++ b/elements/deploy-ironic/init.d/70-ironic-root-device @@ -0,0 +1,115 @@ +CHECK_SIZE=false +CHECK_MODEL=false +CHECK_VENDOR=false +CHECK_UUID=false +CHECK_WWN=false +CHECK_HCTL=false +CHECK_SERIAL=false + + +# URL/Percent decode a text +function urldecode() { + local encoded="${1//+/ }" + printf '%b' "${encoded//%/\x}" +} + + +# Lowercase and url decode the values +function normalize() { + echo `urldecode "${1,,}"` +} + + +function _exec_lsblk() { + lsblk -Pbio $2 /dev/$1 | head -n 1 | grep -Po "(?<=^$2=).*" | tr "\"" " " +} + + +# Get the block device size in GiB +function get_size() { + echo $(( (512 * $(cat /sys/block/$1/size) ) / 2**30)) +} + + +function get_model() { + local file + file=/sys/block/$1/device/model + if [ -f $file ]; then + normalize "$(cat $file)" + fi +} + + +function get_vendor() { + local file + file=/sys/block/$1/device/vendor + if [ -f $file ]; then + normalize "$(cat $file)" + fi +} + + +function get_wwn() { + normalize "$(_exec_lsblk "$1" WWN)" +} + + +function get_serial() { + normalize "$(_exec_lsblk "$1" SERIAL)" +} + + +# Parse all the hints from the Kernel cmdline and set the CHECK_* +# variables +function parse_hints() { + IFS=',' read -ra H <<< "$ROOT_DEVICE" + for i in "${H[@]}"; do + case "$i" in + size=*) + CHECK_SIZE="${i#size=}" + ;; + model=*) + CHECK_MODEL=`normalize "${i#model=}"` + ;; + vendor=*) + CHECK_VENDOR=`normalize "${i#vendor=}"` + ;; + wwn=*) + CHECK_WWN=`normalize "${i#wwn=}"` + ;; + serial=*) + CHECK_SERIAL=`normalize "${i#serial=}"` + ;; + *) + ;; + esac + done +} + + +function get_root_device() { + # Parse the hints + parse_hints + + for DEV in /sys/block/* ; do + DEV_NAME=${DEV##*/} + DEV_PATH=/dev/$DEV_NAME + + # Ignore loop and ram devices + [[ $DEV_NAME = *loop* || $DEV_NAME = *ram* ]] && continue || : + + # Find out if it's a CDROM + TYPE=/sys/block/$DEV_NAME/device/type + [[ -f $TYPE ]] && (( $(cat "$TYPE") == 5 )) && continue || : + + [[ $CHECK_SIZE != false && $(get_size "$DEV_NAME") != $CHECK_SIZE ]] && continue || : + [[ $CHECK_MODEL != false && $(get_model "$DEV_NAME") != $CHECK_MODEL ]] && continue || : + [[ $CHECK_VENDOR != false && $(get_vendor "$DEV_NAME") != $CHECK_VENDOR ]] && continue || : + [[ $CHECK_SERIAL != false && $(get_serial "$DEV_NAME") != $CHECK_SERIAL ]] && continue || : + [[ $CHECK_WWN != false && $(get_wwn "$DEV_NAME") != $CHECK_WWN ]] && continue || : + + # A device that matches all hints was found + echo "$DEV_PATH" + break + done +} diff --git a/elements/deploy-ironic/init.d/80-deploy-ironic b/elements/deploy-ironic/init.d/80-deploy-ironic index 6b7e03fb..94dad011 100644 --- a/elements/deploy-ironic/init.d/80-deploy-ironic +++ b/elements/deploy-ironic/init.d/80-deploy-ironic @@ -1,20 +1,26 @@ readonly IRONIC_API_URL=$(get_kernel_parameter ironic_api_url) readonly IRONIC_BOOT_OPTION=$(get_kernel_parameter boot_option) readonly IRONIC_BOOT_MODE=$(get_kernel_parameter boot_mode) +readonly ROOT_DEVICE=$(get_kernel_parameter root_device) if [ -z "$ISCSI_TARGET_IQN" ]; then err_msg "iscsi_target_iqn is not defined" troubleshoot fi -t=0 -while ! target_disk=$(find_disk "$DISK"); do - if [ $t -eq 10 ]; then - break - fi - t=$(($t + 1)) - sleep 1 -done +target_disk= +if [[ $ROOT_DEVICE ]]; then + target_disk="$(get_root_device)" +else + t=0 + while ! target_disk=$(find_disk "$DISK"); do + if [ $t -eq 10 ]; then + break + fi + t=$(($t + 1)) + sleep 1 + done +fi if [ -z "$target_disk" ]; then err_msg "Could not find disk to use."