F OpenNebula/one#4257: Add non-rootfs resize

Add new context variable 'GROW_FS' which can contain list of directories
(mount-points) separated by spaces.

If GROW_ROOTFS is set to 'YES' then the rootfs will be added in the case
when GROW_FS does not contain '/'.

NOTE: The image has to have the disk name(s) - the underlying device(s)
which are mounted - to follow the simple scheme <name>[<part>] where
name cannot contain any numeric and the part must be only a numeric,
e.g.: /dev/sda1

(Arbitrary disk names are not supported, e.g.: /dev/mapper/luks-1234)

Signed-off-by: Petr Ospalý <pospaly@opennebula.io>
pull/232/head
Petr Ospalý 4 years ago committed by GitHub
parent 4577d94d62
commit 789ac3cf4b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -16,84 +16,264 @@
# limitations under the License. # # limitations under the License. #
#--------------------------------------------------------------------------- # #--------------------------------------------------------------------------- #
# shellcheck disable=SC2001
set -e set -e
GROW_ROOTFS=${GROW_ROOTFS:-YES} GROW_ROOTFS=${GROW_ROOTFS:-YES}
GROW_ROOTFS=${GROW_ROOTFS^^} GROW_ROOTFS=${GROW_ROOTFS^^}
#GROW_FS # list of mountpoints to resize
if [ "${GROW_ROOTFS}" != 'YES' ]; then #
echo 'Skipped root filesystem growing.' >&2 # functions
exit 0 #
fi
# FreeBSD # modified code based on the /etc/rc.d/growfs from FreeBSD
if [ -x /etc/rc.d/growfs ]; then freebsd_growfs()
/etc/rc.d/growfs onestart (
exit $? #
fi # Copyright 2014 John-Mark Gurney
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# $FreeBSD$
#
MOUNT_LINE=$(cat /etc/mtab | grep ' / ' | grep -v '^rootfs') _FS="$1"
DEVICE=$(echo "$MOUNT_LINE" | cut -d' ' -f1)
FSTYPE=$(echo "$MOUNT_LINE" | cut -d' ' -f3)
GROWPART=$(which growpart)
if [ $? -ne 0 ]; then MOUNT_LINE=$(mount -p | awk -v grow_fs="${_FS}" '
echo "growpart command is missing" {if ( $2 == grow_fs) print $1, $3;}
exit 1 ')
fi
if [ $(lvdisplay ${DEVICE} 2>/dev/null | wc -l) -eq 0 ]; then if [ -z "$MOUNT_LINE" ] ; then
DEVICE=$(findmnt -ln -o SOURCE /) echo "GROWFS: No such mountpoint: ${_FS}" >&2
DISK=$(echo "$DEVICE" | sed 's/[0-9]*$//') return 1
PARTITION=$(echo "$DEVICE" | sed "s|^$DISK||") fi
LVM="no"
fi FSDEV=$(echo "$MOUNT_LINE" | cut -d' ' -f1)
FSTYPE=$(echo "$MOUNT_LINE" | cut -d' ' -f2)
if [ "${LVM}" != "no" ]; then case "$FSTYPE" in
if [ -f /etc/debian_version ]; then ufs)
DEVICE=$(mount | grep ' / ' | grep -v '^rootfs'|cut -d' ' -f1) rootdev=${FSDEV#/dev/}
fi ;;
PVRESIZE=$(which pvresize) zfs)
LVEXTEND=$(which lvextend) pool=${FSDEV%%/*}
DISK=$(pvdisplay |grep "PV Name"|awk '{print $3}'|sed 's/.$//') rootdev=$(zpool list -v "$pool" | awk 'END { print $1 }')
PARTITION=$(pvdisplay |grep "PV Name"|awk '{print $3}'| sed "s|^${DISK}||") ;;
PV=$(pvdisplay |grep "PV Name"|awk '{print $3}') *)
LV=$(lvdisplay ${DEVICE} |grep "LV Path"|awk '{print $3}') echo "GROWFS: Mount-point '${_FS}' of type '${FSTYPE}' is not supported!" >&2
return 0
# when PV is on MSDOS logical partition, detect the umbrella esac
# extended partition and grow it first
TABLE=$(parted -s ${DISK} print 2>/dev/null | grep 'Partition Table:' | awk '{print $3}') if [ x"$rootdev" = x"${rootdev%/*}" ]; then
if [ "${TABLE}" = 'msdos' ] && [ ${PARTITION} -gt 4 ]; then # raw device
PARTITION="$(parted -s ${DISK} print | grep 'extended' | awk '{print $1}') $PARTITION" rawdev="$rootdev"
fi else
rawdev=$(glabel status | awk '$1 == "'"$rootdev"'" { print $3 }')
if [ x"$rawdev" = x"" ]; then
echo "GROWFS: Unable to found a device for '${rootdev}'!" >&2
return 1
fi
fi
if [ -n "$DEBUG" ]; then
echo "DEVICE: ${rootdev}"
echo "RAW DEVICE: ${rawdev}"
echo "FSTYPE: ${FSTYPE}"
fi
sysctl -b kern.geom.conftxt | awk '
{
lvl=$1
device[lvl] = $3
type[lvl] = $2
idx[lvl] = $7
parttype[lvl] = $13
if (dev == $3) {
for (i = 1; i <= lvl; i++) {
# resize
if (type[i] == "PART") {
pdev = device[i - 1]
cmd[i] = "gpart resize -i " idx[i] " " pdev
if (parttype[i] == "GPT")
cmd[i] = "gpart recover " pdev " ; " cmd[i]
} else if (type[i] == "LABEL") {
continue
} else {
print "unhandled type: " type[i]
exit 1
}
}
for (i = 1; i <= lvl; i++) {
if (cmd[i])
system(cmd[i])
}
exit 0
}
}' dev="$rawdev"
gpart commit "$rootdev"
case "$FSTYPE" in
ufs)
growfs -y /dev/"$rootdev"
;;
zfs)
zpool online -e "$pool" "$rootdev"
;;
esac
)
#
# main
#
if [ -z "${GROW_FS}" ] && [ "${GROW_ROOTFS}" != 'YES' ]; then
echo 'GROWFS: Skipping filesystem resize' >&2
exit 0
fi fi
if [ -n "$DEBUG" ]; then # add rootfs ('/') to the GROW_FS if GROW_ROOTFS=YES
echo DEVICE: ${DEVICE} if [ "${GROW_ROOTFS}" = 'YES' ] ; then
echo FSTYPE: ${FSTYPE} # duplicates will be removed by the next command
echo DISK: ${DISK} GROW_FS="/ ${GROW_FS}"
echo PARTITION: ${PARTITION}
fi fi
( # sanitize the GROW_FS
for PART in ${PARTITION}; do GROW_FS=$(echo "${GROW_FS}" | sed 's/[[:space:]]\+/\n/g' | sed '/^$/d' | sort -u)
${GROWPART} ${DISK} ${PART}
done OS=$(uname | tr '[:upper:]' '[:lower:]')
case "$OS" in
if [ "${LVM}" != "no" ]; then linux)
${PVRESIZE} ${PV} GROWPART=$(command -v growpart || true)
${LVEXTEND} -l +100%FREE ${LV} if [ -z "${GROWPART}" ]; then
fi echo "GROWFS: growpart command is missing" >&2
) || : # don't fail, partition can be already extended by dracut exit 1
fi
case "${FSTYPE}" in ;;
ext2|ext3|ext4) freebsd)
resize2fs ${DEVICE} if ! [ -x /etc/rc.d/growfs ]; then
;; echo "GROWFS: growfs command is missing" >&2
xfs) exit 1
xfs_growfs / fi
;; ;;
btrfs)
btrfs filesystem resize max /
;;
esac esac
export DEBUG
_exit_result=0
for _FS in ${GROW_FS} ; do
# FreeBSD
if [ "${OS}" = 'freebsd' ]; then
case "$_FS" in
/)
/etc/rc.d/growfs onestart || _exit_result=$?
;;
*)
freebsd_growfs "$_FS" || _exit_result=$?
;;
esac
continue
fi
# Linux
# try /proc/mounts first otherwise fallback to /etc/mtab
MOUNT_LINE=$(\
if [ -e /proc/mounts ] ; then \
cat /proc/mounts ; \
else \
cat /etc/mtab ; \
fi | awk -v grow_fs="${_FS}" '
{if (($0 !~ /rootfs/) && ($2 == grow_fs)) print $1, $3;}
')
if [ -z "$MOUNT_LINE" ] ; then
echo "GROWFS: No such mountpoint: ${_FS}" >&2
_exit_result=1
continue
fi
DEVICE=$(echo "$MOUNT_LINE" | cut -d' ' -f1)
FSTYPE=$(echo "$MOUNT_LINE" | cut -d' ' -f2)
LVM=$(lvdisplay "${DEVICE}" 2>/dev/null | wc -l)
if [ "$LVM" -eq 0 ]; then
DEVICE=$(findmnt -ln -o SOURCE "$_FS")
DISK=$(echo "$DEVICE" | sed 's/[0-9]*$//')
PARTITION=$(echo "$DEVICE" | sed "s|^$DISK||")
LVM="no"
fi
if [ "${LVM}" != "no" ]; then
# TODO: This should be rewritten to accomodate other PVs - this expects
# that PV name ends with zero or exactly one numeric: /dev/sda1
PVRESIZE=$(which pvresize)
LVEXTEND=$(which lvextend)
DISK=$(pvdisplay | awk '/PV Name/ {sub(/.$/, "", $3); print $3;}')
PARTITION=$(pvdisplay | awk -v d="$DISK" '/PV Name/ {sub("^" d, "", $3); print $3;}')
PV=$(pvdisplay | awk '/PV Name/ {print $3}')
LV=$(lvdisplay "${DEVICE}" | awk '/LV Path/ {print $3}')
# when PV is on MSDOS logical partition, detect the umbrella
# extended partition and grow it first
TABLE=$(parted -s "${DISK}" print 2>/dev/null | awk '/Partition Table:/ {print $3}')
if [ "${TABLE}" = 'msdos' ] && [ "${PARTITION}" -gt 4 ]; then
EXTENDED=$(parted -s "${DISK}" print | awk '/extended/ {print $1}')
PARTITION="${EXTENDED} ${PARTITION}"
fi
fi
if [ -n "$DEBUG" ]; then
echo "DEVICE: ${DEVICE}"
echo "FSTYPE: ${FSTYPE}"
echo "DISK: ${DISK}"
echo "PARTITION: ${PARTITION}"
fi
(
for PART in ${PARTITION}; do
${GROWPART} "${DISK}" "${PART}"
done
if [ "${LVM}" != "no" ]; then
${PVRESIZE} "${PV}"
${LVEXTEND} -l +100%FREE "${LV}"
fi
) || : # don't fail, partition can be already extended by dracut
case "${FSTYPE}" in
ext2|ext3|ext4)
resize2fs "${DEVICE}"
;;
xfs)
xfs_growfs "${_FS}"
;;
btrfs)
btrfs filesystem resize max "${_FS}"
;;
esac
done
exit "$_exit_result"

Loading…
Cancel
Save