forked from CaseyLabs/aws-ec2-ebs-automatic-snapshot-bash
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ebs-snapshot-restore.sh
156 lines (138 loc) · 7.04 KB
/
ebs-snapshot-restore.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#!/bin/bash
export PATH=$PATH:/usr/local/bin/:/usr/bin
# Safety feature: exit script if error is returned, or if variables not set.
# Exit if a pipeline results in an error.
set -ue
set -o pipefail
# Automatic EBS Volume Snapshot Clean-Up Script
# Written by: Sally Lehman
# Additonal credits: Log function by Alan Franzoni; Pre-req check by Colin Johnson
#
# PURPOSE: This Bash script replaces the /data dir for MongoDB with one from a backup snapshot.
# - Determine the snapshot IDs of backup using the original hostname and device where the snapshot was taken.
# - The script will then choose an available snapshot within a given date range and create a new volume with it.
# - The script will then unmount the device, detach the current volume, attach the new volume, and mount /data.
# - When finished, monogod will be running again and ready to receive queries on the new snapshot.
# Get Instance Details
instance_id=$(wget -q -O- http://169.254.169.254/latest/meta-data/instance-id)
region=$(wget -q -O- http://169.254.169.254/latest/meta-data/placement/availability-zone | sed -e 's/\([1-9]\).$/\1/g')
availability_zone=$(wget -q -O- http://169.254.169.254/latest/meta-data/placement/availability-zone)
# Set Logging Options
logfile="/var/log/ebs-snapshot-restore.log"
logfile_max_lines="5000"
# Mongo DB data folder associated device
device_id="/dev/xvdf"
# Hostname from which the snapshots originated
snapshot_origin_hostname="ip-10-0-3-68"
# How old of a backup are you looking for?
oldest_backup_age="1" # 1 = 1 day
newest_backup_age="0" # 0 = now
oldest_backup_age_in_seconds=$(date +%s --date "$oldest_backup_age days ago")
newest_backup_age_in_seconds=$(date +%s --date "$newest_backup_age days ago")
## Function Declarations ##
# Function: Setup logfile and redirect stdout/stderr.
log_setup() {
# Check if logfile exists and is writable.
( [ -e "$logfile" ] || touch "$logfile" ) && [ ! -w "$logfile" ] && echo "ERROR: Cannot write to $logfile. Check permissions or sudo access." && exit 1
tmplog=$(tail -n $logfile_max_lines $logfile 2>/dev/null) && echo "${tmplog}" > $logfile
exec > >(tee -a $logfile)
exec 2>&1
}
# Function: Log an event.
log() {
echo "[$(date +"%Y-%m-%d"+"%T")]: $*"
}
# Function: Confirm that the AWS CLI and related tools are installed.
prerequisite_check() {
for prerequisite in aws wget; do
hash $prerequisite &> /dev/null
if [[ $? == 1 ]]; then
echo "In order to use this script, the executable \"$prerequisite\" must be installed." 1>&2; exit 70
fi
done
}
# Function: Find snapshots matching description for the snapshot origin hostname
# and select the first one that is old enough to meet requirements.
choose_snapshot() {
initial_snapshot_description="$snapshot_origin_hostname-$device_id-backup-*"
snapshot_list=$(aws ec2 describe-snapshots --region $region --output=text --filters Name=description,Values=$initial_snapshot_description Name=status,Values='completed' --query Snapshots[].SnapshotId)
log "Available snapshots to restore: $snapshot_list"
snapshot_to_restore=""
for snapshot in $snapshot_list; do
log "Checking $snapshot..."
# Check age of snapshot
snapshot_date=$(aws ec2 describe-snapshots --region $region --output=text --snapshot-ids $snapshot --query Snapshots[].StartTime | awk -F "T" '{printf "%s\n", $1}')
snapshot_date_in_seconds=$(date "--date=$snapshot_date" +%s)
snapshot_description=$(aws ec2 describe-snapshots --snapshot-id $snapshot --region $region --query Snapshots[].Description --output text)
if (( $snapshot_date_in_seconds <= $newest_backup_age_in_seconds )) && (( $snapshot_date_in_seconds >= $oldest_backup_age_in_seconds )); then
snapshot_to_restore=$snapshot
log "Possible snapshot: $snapshot $snapshot_description"
fi
done
log "Selected snapshot: $snapshot_to_restore"
}
# Function: Create a new EBS volume from the chosen backup snapshot
create_volume() {
new_volume_id=$(aws ec2 create-volume --region $region --availability-zone $availability_zone --snapshot-id $snapshot_to_restore --query VolumeId --output text)
log "New volume is $new_volume_id"
aws ec2 wait volume-available --region $region --volume-ids $new_volume_id --query Volumes[].State --output text
check_volume_status=$(aws ec2 describe-volumes --region $region --volume-ids $new_volume_id --query Volumes[].State --output text)
log "New Volume $new_volume_id $check_volume_status"
}
# Function: Umount the block device for the old volume
unmount_mongo_data() {
service mongod stop
umount -d $device_id
sleep 5;
if grep -qs $device_id /proc/mounts; then
log "Old device not unmounted."
exit
else
log "Old device unmounted."
fi
}
# Function: Ensure that /data is now accessible from the new volume
mount_mongo_data() {
#check unmounted
sleep 5;
mount /data
sleep 10;
#ensure mounted
if grep -qs $device_id /proc/mounts; then
log "New device mounted. Starting Mongod..."
service mongod start
else
log "New device not mounted, exiting."
exit
fi
}
# Function: Detach the existing EBS volume from this instance
detach_old_data_volume() {
# Find old_volume_id
old_volume_id=$(aws ec2 describe-volumes --region $region --filters Name=attachment.status,Values="attached" Name=attachment.instance-id,Values=$instance_id Name=attachment.device,Values=$device_id --query Volumes[].VolumeId --output text)
log "Located attached volume $old_volume_id. Detaching..."
detached_volume_status=$(aws ec2 detach-volume --instance-id $instance_id --device $device_id --volume-id $old_volume_id --region $region --query State)
log "$old_volume_id detach initiated, now is $detached_volume_status"
aws ec2 wait volume-available --region $region --volume-id $old_volume_id --query Volumes[].State --output text
detached_volume_status=$(aws ec2 describe-volumes --region $region --volume-id $old_volume_id --query Volumes[].State --output text)
log "$old_volume_id now is $detached_volume_status, and if available then it is successfully detached."
}
# Function: Attaches the newly created EBS volume to this instance and block device
attach_new_data_volume() {
log "Attaching new volume $new_volume_id."
attach_volume_status=$(aws ec2 attach-volume --instance-id $instance_id --device $device_id --volume-id $new_volume_id --region $region --query State)
aws ec2 wait volume-in-use --region $region --volume-id $new_volume_id --query Volumes[].State --output text
attach_volume_status=$(aws ec2 describe-volumes --region $region --volume-id $new_volume_id --query Volumes[].State --output text)
log "$new_volume_id is now $attach_volume_status"
log "New volume $new_volume_id $attach_volume_status, and if in-use than it has been attached."
}
## SCRIPT COMMANDS ##
log_setup
prerequisite_check
choose_snapshot
create_volume
unmount_mongo_data
detach_old_data_volume
attach_new_data_volume
mount_mongo_data
log "DB Restored and ready for use/dump"