You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
226 lines
4.9 KiB
226 lines
4.9 KiB
#!/usr/bin/env bash
|
|
|
|
show_help () {
|
|
cat << EOF
|
|
checkvolumesize 1.0.0
|
|
|
|
Automatically expand Digital Ocean block storage volumes.
|
|
|
|
Usage: checkvolumesize [options]
|
|
|
|
Options:
|
|
|
|
--help | -h | help [Optional] Show this help message
|
|
--token [Required] Digital Ocean API token
|
|
--device [Required] The volume's block device or mount point
|
|
--volume-name [Required] The volume's name
|
|
--volume-region [Required] The volume's region
|
|
--buffer [Optional] The amount of GB to keep available Default: 10
|
|
--log [Optional] Prepend timestamps to stdout
|
|
|
|
Example:
|
|
|
|
checkvolumesize /
|
|
--token bc99be9f73b037da64074472fe58f643e619328b85c5467615964a59abd12029 /
|
|
--device /mnt/block-storage /
|
|
--volume-name volume-sgp1-01 /
|
|
--volume-region sgp1 /
|
|
--buffer 10
|
|
|
|
GitHub: https://github.com/lukechilds/autoscale-do-block-storage
|
|
EOF
|
|
}
|
|
|
|
# Parse options
|
|
POSITIONAL=()
|
|
while [[ $# -gt 0 ]]; do
|
|
key="$1"
|
|
|
|
BUFFER=10
|
|
LOG=false
|
|
|
|
case $key in
|
|
--help|-h|help)
|
|
show_help
|
|
exit
|
|
;;
|
|
|
|
--token)
|
|
TOKEN="$2"
|
|
shift
|
|
shift
|
|
;;
|
|
|
|
--device)
|
|
DEVICE="$2"
|
|
shift
|
|
shift
|
|
;;
|
|
|
|
--volume-name)
|
|
VOLUME_NAME="$2"
|
|
shift
|
|
shift
|
|
;;
|
|
|
|
--volume-region)
|
|
VOLUME_REGION="$2"
|
|
shift
|
|
shift
|
|
;;
|
|
|
|
--buffer)
|
|
BUFFER="$2"
|
|
shift
|
|
shift
|
|
;;
|
|
|
|
--log)
|
|
LOG=true
|
|
shift
|
|
shift
|
|
;;
|
|
|
|
*)
|
|
POSITIONAL+=("$1")
|
|
shift
|
|
;;
|
|
esac
|
|
done
|
|
set -- "${POSITIONAL[@]}"
|
|
|
|
log () {
|
|
prefix=""
|
|
if [[ "$LOG" = true ]]; then
|
|
prefix="$(date "+%Y-%m-%d %H:%M:%S") "
|
|
fi
|
|
echo $prefix$@
|
|
}
|
|
|
|
check_root () {
|
|
if [[ $UID != 0 ]]; then
|
|
log "This script must be run as root"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
check_dependencies () {
|
|
for cmd in "$@"; do
|
|
if ! command -v $cmd >/dev/null 2>&1; then
|
|
log "This script requires \"${cmd}\" to be installed"
|
|
exit 1
|
|
fi
|
|
done
|
|
}
|
|
|
|
check_options () {
|
|
if [[ -z $TOKEN || -z $DEVICE || -z $VOLUME_NAME || -z $VOLUME_REGION ]]; then
|
|
log 'You are missing required options'
|
|
echo
|
|
show_help
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
digital_ocean_api () {
|
|
endpoint=$1
|
|
post_data=$2
|
|
|
|
method="GET"
|
|
if [[ $post_data ]]; then
|
|
method="POST"
|
|
fi
|
|
|
|
args=()
|
|
args+=("--silent")
|
|
args+=("-X" $method)
|
|
args+=("-H" "Content-Type: application/json")
|
|
args+=("-H" "Authorization: Bearer ${TOKEN}")
|
|
if [[ $post_data ]]; then
|
|
args+=("-d" $post_data)
|
|
fi
|
|
args+=("https://api.digitalocean.com/v2/${endpoint}")
|
|
|
|
curl "${args[@]}"
|
|
}
|
|
|
|
bytes_to_gigabytes () {
|
|
bytes=$1
|
|
|
|
expr $bytes / 1024 / 1024
|
|
}
|
|
|
|
check_device_free_space () {
|
|
device=$1
|
|
|
|
bytes_free=$(df --output=avail $device | tail -n 1)
|
|
bytes_to_gigabytes $bytes_free
|
|
}
|
|
|
|
mountpoint_to_device () {
|
|
mountpoint=$1
|
|
|
|
df --output=source $mountpoint | tail -n 1
|
|
}
|
|
|
|
main () {
|
|
check_root
|
|
check_dependencies curl jq expr resize2fs
|
|
check_options
|
|
|
|
# Check available volume space
|
|
log "Checking available space on device \"${DEVICE}\" is above ${BUFFER}GB requirement..."
|
|
volume_free_space=$(check_device_free_space $DEVICE)
|
|
if [[ $volume_free_space -gt $BUFFER ]]; then
|
|
log "${volume_free_space}GB available, all good!"
|
|
return
|
|
fi
|
|
log "Only ${volume_free_space}GB available, volume resize required"
|
|
|
|
# Save start time
|
|
start_time=$SECONDS
|
|
|
|
# Get volume data
|
|
log "Getting data for volume \"${VOLUME_NAME}\" in region \"${VOLUME_REGION}\"..."
|
|
volume_json=$(digital_ocean_api "volumes?region=${VOLUME_REGION}" | jq -r --arg VOLUME_NAME "${VOLUME_NAME}" '.volumes | .[] | select(.name==$VOLUME_NAME)')
|
|
volume_id=$(echo $volume_json | jq -r .id)
|
|
volume_size=$(echo $volume_json | jq -r .size_gigabytes)
|
|
log "Volume ID is \"${volume_id}\" and is currently ${volume_size}GB"
|
|
|
|
# Increase volume size
|
|
new_volume_size=$(expr $volume_size + $BUFFER)
|
|
log "Increasing volume size to ${new_volume_size}GB..."
|
|
action_json=$(digital_ocean_api "volumes/${volume_id}/actions" '{"type":"resize","size_gigabytes":'$new_volume_size'}')
|
|
action_id=$(echo $action_json | jq -r '.action.id')
|
|
log "Created action \"${action_id}\""
|
|
|
|
# Wait for volume resize
|
|
log "Waiting for action to complete..."
|
|
while true; do
|
|
resize_status=$(digital_ocean_api "actions/$action_id" | jq -r '.action.status')
|
|
if [[ "${resize_status}" == "completed" ]]; then
|
|
break
|
|
fi
|
|
sleep 1
|
|
done
|
|
log "Volume resize complete!"
|
|
|
|
# Resize filesystem
|
|
log "Resizing filesystem..."
|
|
sudo resize2fs $(mountpoint_to_device $DEVICE) 2>&1 | while read line; do
|
|
if [[ "${line}" != "" ]]; then
|
|
log $line
|
|
fi
|
|
done
|
|
log "Filesystem resize complete!"
|
|
|
|
# Show new available space on completion
|
|
new_free_space=$(check_device_free_space $DEVICE)
|
|
log "Device \"${DEVICE}\" now has ${new_free_space}GB available"
|
|
|
|
# Show duration
|
|
duration=$(expr $SECONDS - $start_time)
|
|
log "Completed in ${duration} seconds"
|
|
}
|
|
|
|
main
|
|
|