Skip to content

Instantly share code, notes, and snippets.

@kwilczynski
Last active June 23, 2021 16:21
Show Gist options
  • Select an option

  • Save kwilczynski/8e7807b22148fe2c1631 to your computer and use it in GitHub Desktop.

Select an option

Save kwilczynski/8e7807b22148fe2c1631 to your computer and use it in GitHub Desktop.
AWS EC2, Ephemeral volumes, create RAID level 0 (stripe), etc.
#!/bin/bash
set -u
set -e
set -o pipefail
export PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
readonly LOCK_FILE='/tmp/.format-volume'
readonly EC2_METADATA_URL='http://169.254.169.254/latest/meta-data'
# Make sure files are 644 and directories are 755.
umask 022
# Check whether this script was already run?
if [[ -f $LOCK_FILE ]]; then
echo "Previous (completed at "$(. $LOCK_FILE ; echo $DATE)") run has been detected, aborting ..."
exit 1
fi
# Get current time.
readonly TIMESTAMP=$(TZ=UTC date +%s)
declare -a DEVICE_MAPPING=()
# Get the list of devices from Amazon ...
DEVICE_MAPPING=($(
curl -s ${EC2_METADATA_URL}/block-device-mapping/ | \
awk '/ephemeral[[:digit:]]+/ { print }'
))
if (( ${#DEVICE_MAPPING[@]} < 1 )); then
echo 'Unable to find any attached volumes, nothing to do.'
exit 0
fi
STORAGE_DEVICES_COUNT=0
declare -a STORAGE_DEVICES=()
# Try to detect the device (based on the current root volume) taking into
# the account different naming scheme e.g., /dev/sdb vs /dev/xvdb, etc.
DEVICE_SCHEME='sd'
if blkid | cut -d' ' -f 1 | grep -qF '/dev/xvda'; then
DEVICE_SCHEME='xvd'
fi
# ... and validate whether a particular device actually
# exists which is not always the case, as sometimes the
# meta-data service would return data where no actual
# device is present.
for device in "${DEVICE_MAPPING[@]}"; do
DEVICE=$(curl -s ${EC2_METADATA_URL}/block-device-mapping/${device})
# Got a device? Great.
if [[ -n $DEVICE ]]; then
STORAGE_DEVICES+=( "/dev/$(echo $DEVICE | sed -e "s/sd/${DEVICE_SCHEME}/")" )
fi
done
# How may devices do we have at our disposal? This is
# needed to setup RAID (stripe) later.
STORAGE_DEVICES_COUNT=${#STORAGE_DEVICES[@]}
# Make sure to sort the devices list.
STORAGE_DEVICES=( $(printf '%s\n' "${STORAGE_DEVICES[@]}" | sort) )
if (( $STORAGE_DEVICES_COUNT < 1 )); then
echo "The attached storage volumes could not be found, aborting..."
exit 1
fi
# Make sure "noop" scheduler is set. Alternatively,
# the "deadline" could be used to potentially reduce
# I/O latency in some cases. Also, set read-ahead
# value to double the default.
for device in "${STORAGE_DEVICES[@]}"; do
echo 'noop' > /sys/block/${device##*/}/queue/scheduler
blockdev --setra 512 $device
done
# Remove anything that looks like a floppy drive.
sed -i -e \
'/^.\+fd0/d;/^.\*floppy0/d' \
/etc/fstab
# Re-format /etc/fstab to fix whitespaces there.
sed -i -e \
'/^#/!s/\s\+/\t/g' \
/etc/fstab
# Make sure that attached volume really is not mounted anywhere.
for device in "${STORAGE_DEVICES[@]}"; do
if grep -q $device /proc/mounts; then
# Sort by length, in order to unmount longest path first.
grep $device /proc/mounts | awk '{ print length, $2 }' | \
sort -gr | cut -d' ' -f2- | xargs umount -f || true
# Remove from /etc/fstab, if needed.
sed -i -e \
"/^$(echo $device | sed -e 's/\//\\\//g')/d" \
/etc/fstab
fi
done
# Make sure that /mnt and /srv are not mounted.
for directory in /media /mnt /srv; do
# Nothing of value should be there in these directories.
if [[ -d $directory ]]; then
umount -f $directory || true
rm -rf ${directory}/*
else
mkdir -p $directory
fi
chown root: $directory
chmod 755 $directory
done
# Wipe any old file system signature, just in case.
for device in "${STORAGE_DEVICES[@]}"; do
wipefs -a$(wipefs -f &>/dev/null && echo 'f') $device || true
done
# Make sure to install dependencies if needed.
REFRESH_YUM=0
for package in mdadm xfsprogs; do
if ! rpm -q $package &>/dev/null; then
if (( $REFRESH_YUM < 1 )); then
yum makecache
REFRESH_YUM=1
fi
yum install -y $package
fi
done
# Grab first device (to be overridden later, if needed).
DEVICE=${STORAGE_DEVICES[0]}
# Create RAID0 if there is more than one device.
if (( $STORAGE_DEVICES_COUNT > 1 )); then
# Override the device that will be used when mounting.
DEVICE='/dev/md0'
# Stop any RAID array that might be running,
# although there should be no arrays present.
if [[ -b $DEVICE ]]; then
rm -f /etc/mdadm.conf
for option in '--stop' '--remove'; do
mdadm $option --force $DEVICE || true
done
mdadm --zero-superblock \
$(printf '%s\n' "${STORAGE_DEVICES[@]}") || true
fi
mdadm --create --verbose $DEVICE --level=stripe --chunk=256 \
--raid-devices=${STORAGE_DEVICES_COUNT} \
$(printf '%s\n' "${STORAGE_DEVICES[@]}")
# Activate device immediately.
mdadm --readwrite $DEVICE || true
# Display details about the assembled array.
mdadm --detail $DEVICE
# Set read-ahead that makes sense for RAID device.
blockdev --setra 65536 $DEVICE
# Populate the /etc/mdadm.conf file.
cat <<'EOF' | tee /etc/mdadm.conf
DEVICE /dev/sd[a-z] /dev/xvd[a-z]
CREATE owner=root group=disk mode=0660 auto=yes
HOMEHOST <system>
MAILADDR root
EOF
mdadm --detail --scan >> /etc/mdadm.conf
chown root: /etc/mdadm.conf
chmod 644 /etc/mdadm.conf
cat /proc/mdstat
fi
# By default, the attached volume is formatted with ext3.
mkfs.xfs -q -L '/srv' -f $DEVICE
# Add extra volume.
cat <<EOS | sed -e 's/\s\+/\t/g' | tee -a /etc/fstab
$DEVICE /srv xfs defaults,noatime,nodiratime,nobarrier,nofail,comment=cloudconfig 0 2
EOS
mount /srv
xfs_info $DEVICE
sync
sync
# Update initramfs for all kernels ...
while read version; do
version=${version#*-}
dracut -a mdraid --mdadmconf -f -H /boot/initramfs-${version}.img $version
ls -l /boot/initramfs-${version}.img
done < <(rpm -qa kernel)
# Release I/O buffer cache.
echo '3' > /proc/sys/vm/drop_caches
# Mount everything else...
mount -a
# Display mount points and free space.
mount
printf "\n"
df -h
cat <<EOF | tee $LOCK_FILE
TIMESTAMP=$TIMESTAMP
DATE="$(date -d @${TIMESTAMP})"
EOF
chown root:root $LOCK_FILE
chmod 644 $LOCK_FILE
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment