Skip to content

Instantly share code, notes, and snippets.

@m0n5t3r
Last active January 23, 2017 09:38
Show Gist options
  • Save m0n5t3r/5173cd38f336c4525cf25a77cb235378 to your computer and use it in GitHub Desktop.
Save m0n5t3r/5173cd38f336c4525cf25a77cb235378 to your computer and use it in GitHub Desktop.
AWS consistent snapshot and expire script; replaces not-quite-working ec2-consistent-snapshot and ec2-expire-snapshots (both don't work in eu-central-1, the latter tries to manage all snapshots)
#!/bin/bash
#
# Copyright: 2016 Sabin Iacob
#
# 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 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.
# you'll need aws-cli set up and working, and a user that has at least:
# * ec2 read-only policy
# * custom policy that allows these actions:
# - "ec2:CopySnapshot",
# - "ec2:CreateSnapshot",
# - "ec2:DeleteSnapshot",
# - "ec2:CreateTags"
# The retention policy is hardcoded in filter_snapshots; this version is supposed
# to run every hour and keep hourly snapshots for 24h, daily snapshots for 7 days
# and weekly snapshots for 30 days
export PATH=/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin HOME=/root USER=root
tty -s || exec &> >(logger -t such_backup)
HOSTNAME=$(hostname)
NOW=$(date +%Y-%m-%d-%H:%M:%S)
TO_SNAPSHOT=$*
if [ -z "$TO_SNAPSHOT" ]; then
echo "Usage: $0 mountpoint [mountpoint ...]"
echo
echo "Nothing to do!"
exit 1
fi
INSTANCE_ID=$(ec2metadata --instance-id)
function snapshot_fs() {
vol_id=$1
d=$2
sync
fsfreeze -f $d
snap_id=$(aws ec2 create-snapshot --volume-id $vol_id --description "$HOSTNAME $NOW" --output text | awk '{print $5}')
fsfreeze -u $d
aws ec2 create-tags --resources $snap_id --tags "Key=backup,Value=true" --output text
}
function fetch_snapshots() {
vol_id=$1
aws ec2 describe-snapshots --filters "Name=volume-id,Values=$vol_id" "Name=status,Values=completed" "Name=tag-key,Values=backup" --output text | awk '/SNAPSHOTS/ {print $(NF-4), $(NF-3)}'
}
function filter_snapshots() {
NOW=$(date +%s)
while read snap_id dt; do
ts=$(date -d $dt +%s)
h=$(date -d $dt +%H | sed -e 's/^0//')
dow=$(date -d $dt +%u)
age=$((NOW - ts))
if (((age > 2592000) || (age > 86400 && h > 0) || (age > 604800 && dow > 1))); then
echo $snap_id
fi
done
}
for d in $TO_SNAPSHOT; do
dev=$(df $d | awk '/xvd/{gsub("[0-9]+$", "", $1); gsub("xv", "s", $1); print $1;}')
rootdev=$(echo $dev | sed -e 's/[0-9]$//g')
if [ -e "$rootdev" ]; then
dev=$rootdev
fi
vol_id=$(aws ec2 describe-volumes --filters "Name=attachment.instance-id,Values=$INSTANCE_ID" "Name=attachment.device,Values=$dev" --output text | awk '/^VOLUMES/{ print $8; }')
snapshot_fs $vol_id $d
to_delete=$(fetch_snapshots $vol_id | filter_snapshots)
for snap_id in $to_delete; do
aws ec2 delete-snapshot --snapshot-id $snap_id --output text
done
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment