Skip to content

Instantly share code, notes, and snippets.

@a13m
Last active August 29, 2015 14:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save a13m/715bf631ba3732aee7ab to your computer and use it in GitHub Desktop.
Save a13m/715bf631ba3732aee7ab to your computer and use it in GitHub Desktop.
#!/bin/bash
#--
# Copyright 2014 Red Hat, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#++
# Purpose: This script grows the root filesystem and sets up LVM volumes
# for docker metadata and data.
# Author: Andy Grimm <agrimm@redhat.com>
set -e
# Read the config. Currently supported options:
# DEVS: A quoted, space-separated list of devices to be used. This currently
# expects the devices to be unpartitioned drives. If "VG" is not
# specified, then use of the root disk's extra space is implied.
#
# VG: The volume group to use for docker storage. Defaults to the volume
# group where the root filesystem resides. If VG is specified and the
# volume group does not exist, it will be created (which requires that
# "DEVS" be nonempty, since we don't currently support putting a second
# partition on the root disk).
#
# The options below should be specified as values acceptable to 'lvextend -L':
#
# ROOT_SIZE: The size to which the root filesystem should be grown.
#
# DATA_SIZE: The desired size for the docker data LV. Defaults to using all
# free space in the VG after the root LV and docker metadata LV
# have been allocated/grown.
#
# Other possibilities:
# * Support lvm raid setups for docker data? This would not be very difficult
# if given multiple PVs and another variable; options could be just a simple
# "mirror" or "stripe", or something more detailed.
source /etc/sysconfig/docker-storage-setup
# Read mounts
ROOT_DEV=$( awk '$2 ~ /^\/$/ && $1 !~ /rootfs/ { print $1 }' /proc/mounts )
ROOT_VG=$( lvs --noheadings -o vg_name $ROOT_DEV )
ROOT_PVS=$( pvs --noheadings -o pv_name,vg_name | awk "\$2 ~ /^$ROOT_VG\$/ { print \$1 }" )
VG_EXISTS=
if [ -z "$VG" ]; then
VG=$ROOT_VG
VG_EXISTS=1
else
for vg_name in $( vgs --noheadings -o vg_name ); do
if [ "$vg_name" == "$VG" ]; then
VG_EXISTS=1
break
fi
done
fi
if [ -z "$DEVS" ] && [ -z "$VG_EXISTS" ]; then
echo "Specified volume group $VG does not exists, and no devices were specified" >&2
exit 1
fi
PVS=
GROWPART=
if [ -n "$DEVS" ] ; then
for dev in $DEVS; do
if expr match $dev ".*[0-9]"; then
echo "Partition specification unsupported at this time." >&2
exit 1
fi
# Use a single partition of a whole device
# TODO:
# * Consider gpt, or unpartitioned volumes
# * Error handling when partition(s) already exist
# * Deal with loop/nbd device names. See growpart code
PARTS=$( awk "\$4 ~ /"$( basename $dev )"[0-9]/ { print \$4 }" /proc/partitions )
if [ -n "$PARTS" ]; then
echo "$dev has partitions: $PARTS"
exit 1
fi
size=$(( $( awk "\$4 ~ /"$( basename $dev )"/ { print \$3 }" /proc/partitions ) * 2 - 2048 ))
cat <<EOF | sfdisk $dev
unit: sectors
${dev}1 : start= 2048, size= ${size}, Id=8e
EOF
pvcreate ${dev}1
PVS="$PVS ${dev}1"
done
if [ -z "$VG_EXISTS" ]; then
vgcreate $VG $PVS
else
# TODO:
# * Error handling when PV is already part of a VG
vgextend $VG $PVS
fi
GROWPART=1
elif [ "$ROOT_VG" == "$VG" ]; then
GROWPART=1
fi
# Note that growpart is only variable here because we may someday support
# using separate partitions on the same disk. Today we fail early in that
# case. Also note that the way we are doing this, it should support LVM
# RAID for the root device. In the mirrored or striped case, we are growing
# partitions on all disks, so as long as they match, growing the LV should
# also work.
if [ -n "$GROWPART" ]; then
for pv in $ROOT_PVS; do
# Split device & partition. Ick.
echo growpart $( echo $pv | sed -r 's/([^0-9]*)([0-9]+)/\1 \2/' )
echo pvresize $pv
done
fi
# NB: We are growing root here first, because when root and docker share a
# disk, we'll default to giving docker "everything else." This will be a
# problem if someone tries to assign root a value like"100%FREE".
if [ -n "$ROOT_SIZE" ]; then
# TODO: Error checking if specified size is <= current size
lvextend -L $ROOT_SIZE $ROOT_DEV || true
fi
# Reserve 0.1% of the free space in the VG for docker metadata.
# Calculating the based on actual data size might be better, but is
# more difficult do to the range of possible inputs.
VG_FREE_EXTS=$( vgs --noheadings --nosuffix --units s -o vg_free $VG )
META_SIZE=$(( $VG_FREE_EXTS / 1000 + 1 ))
lvcreate -l ${META_SIZE}S -n docker-meta $VG
if [ -n "$DATA_SIZE" ]; then
# TODO: Error handling when DATA_SIZE > available space.
lvcreate -L $DATA_SIZE -n docker-data $VG
else
lvcreate -l "100%FREE" -n docker-data $VG
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment