From b16e4048672679b16223e55d768bee0d7d877ced Mon Sep 17 00:00:00 2001 From: Ian Kelling Date: Mon, 15 Feb 2016 15:14:28 -0800 Subject: [PATCH] add resize support, tested with 1 disk so far --- fai/config/hooks/partition.DEFAULT | 38 +++-- fresize | 240 +++++++++++++++++++++++++++++ 2 files changed, 261 insertions(+), 17 deletions(-) create mode 100755 fresize diff --git a/fai/config/hooks/partition.DEFAULT b/fai/config/hooks/partition.DEFAULT index 5d4684c..ee19894 100755 --- a/fai/config/hooks/partition.DEFAULT +++ b/fai/config/hooks/partition.DEFAULT @@ -10,11 +10,11 @@ skiptask partition ||: # for running out of fai #### begin configuration -bootn=1 +bootn=3 +rootn=1 swapn=2 -rootn=3 bios_grubn=4 -boot_end=804 +boot_mib=750 lastn=$bios_grubn if ifclass VM; then @@ -80,14 +80,17 @@ fi crypt=/dev/mapper/crypt_dev_${d##/dev/}a$rootn - -if ifclass frodo; then - # next upgrade is prolly 16 gigs of memory, across ~8 devices - swap_end=$((3500 + boot_end)) -else - # 1.5 x based on https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/Installation_Guide/sect-disk-partitioning-setup-x86.html#sect-custom-partitioning-x86 - swap_end=$(( $(grep ^MemTotal: /proc/meminfo| awk '{print $2}') * 3/(${#devs[@]} * 2 ) / 1000 + boot_end )) -fi +bios_grub_end=4 +# 1.5 x based on https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/Installation_Guide/sect-disk-partitioning-setup-x86.html#sect-custom-partitioning-x86 +swap_mib=$(( $(grep ^MemTotal: /proc/meminfo | \ + awk '{print $2}') * 3/(${#devs[@]} * 2 ) / 1024 )) +# parted will round up the disk size. Do -1 so we can have +# fully 1MiB unit partitions for easy resizing of the last partition. +# Otherwise we would pass in -0 for the end argument for the last partition. +disk_mib=$(( $(parted -m ${devs[0]} unit MiB print | \ + sed -nr "s#^${devs[0]}:([0-9]+).*#\1#p") - 1)) +root_end=$(( disk_mib - swap_mib - boot_mib )) +swap_end=$(( root_end + swap_mib)) mkdir -p /tmp/fai shopt -s nullglob @@ -97,19 +100,20 @@ if $partition; then done for dev in ${devs[@]}; do parted -s $dev mklabel gpt - # gpt ubuntu cloud image uses ~4. fai uses 1 MiB. ehh, i'll do 4. - # also, using MB instead of MiB causes complains about alignment. + # gpt ubuntu cloud image uses ~4. fai uses 1 MiB. + # I read something in the parted manual saying cheap flash media + # likes to start at 4. + # MiB because parted complains about alignment otherwise. pcmd="parted -a optimal -s -- $dev" - $pcmd mkpart primary "ext3" 4MB ${boot_end}MiB - $pcmd mkpart primary "linux-swap" ${boot_end}MiB ${swap_end}MiB - $pcmd mkpart primary "" ${swap_end}MiB -0 + $pcmd mkpart primary "ext3" 4MiB ${root_end}MiB + $pcmd mkpart primary "linux-swap" ${root_end}MiB ${swap_end}MiB + $pcmd mkpart primary "" ${swap_end}MiB ${disk_mib}MiB $pcmd mkpart primary "" 1MiB 4MiB $pcmd set $bios_grubn bios_grub on $pcmd set $bootn boot on # generally not needed on modern systems # the mkfs failed randomly on a vm, so I threw a sleep in here. sleep .1 - luks_dev=$dev$rootn yes YES | cryptsetup luksFormat $luks_dev $luks_dir/host-$HOSTNAME \ -c aes-cbc-essiv:sha256 -s 256 || [[ $? == 141 ]] diff --git a/fresize b/fresize new file mode 100755 index 0000000..90f1998 --- /dev/null +++ b/fresize @@ -0,0 +1,240 @@ +#!/bin/bash + +shopt -s extdebug +bash-trace() { + # shows function args when: shopt -s extdebug + local -i argc_index=0 arg frame i start=${1:-1} max_indent=8 indent + local source + local extdebug=false + if [[ $(shopt -p extdebug) == *-s* ]]; then + extdebug=true + fi + + for ((frame=0; frame < ${#FUNCNAME[@]}-1; frame++)); do + argc=${BASH_ARGC[frame]} + argc_index+=$argc + ((frame < start)) && continue + if (( ${#BASH_SOURCE[@]} > 1 )); then + source="${BASH_SOURCE[frame+1]}:${BASH_LINENO[frame]}:" + fi + indent=$((frame-start+1)) + indent=$((indent < max_indent ? indent : max_indent)) + printf "%${indent}s↳%sin \`%s" '' "$source" "${FUNCNAME[frame]}" + if $extdebug; then + for ((i=argc_index-1; i >= argc_index-argc; i--)); do + printf " %s" "${BASH_ARGV[i]}" + done + fi + echo \' + done +} + + +errcatch() { + set -E; shopt -s extdebug + _err-trap() { + err=$? + exec >&2 + echo "${BASH_SOURCE[1]}:${BASH_LINENO[0]}:in \`$BASH_COMMAND' returned $err" + bash-trace 2 + echo "$0: exiting with code $err" + exit $err + } + trap _err-trap ERR + set -o pipefail +} + +errcatch + +[[ $EUID == 0 ]] || sudo "$BASH_SOURCE" "$@" + +usage() { + cat </dev/null; then + echo "$0: error: install parted" + exit 1 +fi + +case $2 in swap|boot) : ;; *) echo "$0: error: bad 2nd arg"; usage 1 ;; esac + +#### end arg error checking #### + + +boot=true +[[ $2 == boot ]] || boot=false + +#size=${x#[+-]} +op_size=$1 # operator plus size +[[ $op_size != *g ]] || op_size=$(( ${op_size%g} / 1024 )) +size=${op_size#[+-]} + +if [[ $op_size == +* ]]; then + op_size_rev=-$size # rev = reverse + grow=true +else + op_size_rev=+$size + grow=false +fi + +##### end command line parsing ######## + +rootn=1 +swapn=2 +bootn=3 +needs_reboot=false + +pmk() { + part=$1 + start_op=$2 + end_op=$3 + read start end < <(echo ${ptable[$part]}) + p mkpart primary "$4" $((start $start_op)) $((end $end_op)) +} + + +swapoff -a + +while read devid dev; do + if $dry_run; then + e() { echo "+ $@"; } + else + e() { echo "+ $@"; "$@"; } + fi + ptable=() + while IFS=: read id start end _; do + [[ $id == [0-9] ]] || continue + end=${end%MiB} + start=${start%MiB} + start=${start%.*} # small enough number that parted uses a decimal + ptable[$id]="$start $end" + done < <(parted -m /dev/$dev unit MiB print) + parted /dev/$dev unit MiB print | tee /root/backup_partition + p() { e parted -a optimal -s -- /dev/$dev unit MiB "$@"; } + e systemctl stop systemd-cryptsetup@crypt_swap_$dev$swapn + sleep 1 + # These partition comments seems a little verbose now, but I bet they + # will be helpfull if I read this in more than a week from now. + # <> = deleted partition, () = partition + p rm $swapn # ( root )< swap >( boot ) + + root_resize_cmd="e btrfs fi resize $devid:$op_size_rev /" + if $grow; then $root_resize_cmd; fi + # if $grow; then + # < root >< swap >( boot ) + # ( root ) >< swap >( boot ) + # else + # < root >< swap >( boot ) + # ( root >< ) swap >( boot ) + + out=$(p rm $rootn 2>&1) + echo "$out" + + pmk $rootn "" $op_size_rev + if ! $grow; then + if echo "$out" | \ + grep "but we have been unable to inform the kernel" &>/dev/null; then + e systemctl mask dev-mapper-crypt_swap_$dev$swapn.swap + e systemctl mask systemd-cryptsetup@crypt_swap_$dev$swapn.service + if ! $needs_reboot; then + needs_reboot=true + echo "$0: reboot and run /root/finish-resize to finish. +The following commands are what will be executed:" + rm -rf /root/finish-resize + cat >/root/finish-resize <<'EOF' +#!/bin/bash -x +set -eE -o pipefail +trap 'echo "$0:$LINENO:error: \"$BASH_COMMAND\" returned $?"' ERR +EOF + chmod +x /root/finish-resize + fi + e() { echo "$@" | tee -a /root/finish-resize; } + e systemctl unmask systemd-cryptsetup@crypt_swap_$dev$swapn.service + e systemctl unmask dev-mapper-crypt_swap_$dev$swapn.swap + # todo, disable swap for the next boot. currently have to wait + # 1:30 for it to fail. + fi + $root_resize_cmd + fi + if $boot; then + boot_devid=$(btrfs fi show /boot | \ + sed -rn "s#^\s*devid\s+(\S+)\s.*$dev[0-9]#\1#p") + + if ! $grow; then + # shrink boot, move it to a temp file + e btrfs fi resize $boot_devid:$op_size /boot + temp_boot=/root/temp_boot_dd + e dd bs=1M if=/dev/$dev$bootn of=$temp_boot count=$size + fi + # if $grow; then + # ( root ) >< swap >< boot > + # ( root )( >< swap ) >< boot > + # ( root )( >< swap )( >< boot ) + # else + # ( root >< ) swap >< boot > + # ( root >< )( swap >< ) boot > + # ( root >< )( swap >< )( boot ) + e umount /boot + p rm $bootn + pmk $swapn $op_size_rev $op_size_rev "linux-swap" + pmk $bootn $op_size_rev "" + + if $grow; then + e dd bs=1M if=/dev/$dev$bootn of=/dev/$dev$bootn skip=$size + e btrfs fi resize $boot_devid:$op_size /boot + else + e dd bs=1M if=$temp_boot of=/dev/$dev$bootn + fi + e mount /boot + else + # if $grow; then ( root )( >< swap )( boot ) + # else ( root >< )( swap )( boot ) + pmk $swapn $op_size_rev "" "linux-swap" + fi +done < <(btrfs fi show / | \ + sed -nr 's#^\s*devid\s*(\S+)\s.*_([^_ ]+)[0-9]\s*$#\1 \2#p') + +if $boot; then + e rm -rf $temp_boot + e rm /root/finish-resize +fi + +if $needs_reboot; then + echo "$0: reminder, reboot then /root/finish-resize" +fi + +#for dev in ${devs[@]}; do -- 2.30.2