├── README.md └── exportEC2VolumeImage /README.md: -------------------------------------------------------------------------------- 1 | # exportEC2VolumeImage 2 | A Bash script which uses AWS CLI to create an image of an AWS EC2 volume and store it *outside* of the AWS environment. 3 | 4 | -------------------------------------------------------------------------------- /exportEC2VolumeImage: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # exportEC2VolumeImage: Create an image of an Amazon EC2 volume, compress it, and send it to the destination of your choice 3 | # 4 | # 5 | # eric.smith@cyberstoics.io 6 | # inital release: 6 Feb 2019 7 | # 8 | # This script requires the "aws" command line tool to be installed and configured with 9 | # access and secret keys with permission to perform EC2 operations. 10 | # See https://aws.amazon.com/cli/ for further details 11 | # 12 | # This program is free software: you can redistribute it and/or modify 13 | # it under the terms of the GNU General Public License as published by 14 | # the Free Software Foundation, either version 3 of the License, or 15 | # (at your option) any later version. 16 | # 17 | # This program is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | # GNU General Public License for more details. 21 | # 22 | # You should have received a copy of the GNU General Public License 23 | # along with this program. If not, see . 24 | 25 | # program configs: 26 | 27 | # mount point 28 | mountPoint="/dev/xvdp" 29 | 30 | # Append a timestamp to the user-provideed filename 31 | suffix=$(date +%Y%m%d_%H%M%S) 32 | 33 | if [ -b $mountPoint ]; then 34 | echo "A device is already present at ${mountPoint}. Exiting." 35 | exit 0 36 | fi 37 | 38 | 39 | # Check for the right number of command line args 40 | 41 | if [ "$#" -ne 4 ]; then 42 | echo "usage: aws-create-image volume-id region this-instance-id scratch" 43 | exit 0 44 | fi 45 | 46 | 47 | # make sure scratch is a directory 48 | 49 | if [ ! -d "${4}" ]; then 50 | echo "Scratch folder doesn't appear to be a folder. Exiting." 51 | exit 0 52 | fi 53 | 54 | 55 | 56 | # Some easier-to-follow variable names 57 | 58 | volumeId=${1} 59 | region=${2} 60 | buildId=${3} 61 | 62 | # Build a meaningful filename for the image file 63 | filename="${4}/ec2VolImg.${volumeId}.${suffix}.img" 64 | 65 | # Verify that the volume is valid 66 | 67 | describeVolumes=$(aws ec2 describe-volumes --output text --region ${region} --volume-id ${volumeId} 2>&1) 68 | 69 | if [ "$?" -ne 0 ]; then 70 | echo "The specified region or volumeID is not valid, or the AWS CLI tool is not configured properly." 71 | echo $describeVolumes 72 | exit 255 73 | fi 74 | 75 | availabilityZone=$(echo ${describeVolumes} | cut -d\ -f2) 76 | 77 | echo "Volume ${volumeId} is in availability zone ${availabilityZone}" 78 | 79 | 80 | # Create a snapshot from the volume 81 | createSnapshot=$(aws ec2 create-snapshot --output text --region ${region} --volume-id ${volumeId} --description "SnapImg") 82 | 83 | if [ "$?" -ne 0 ]; then 84 | echo "The specified region or volumeID is not valid, or the AWS CLI tool is not configured properly." 85 | exit 255 86 | fi 87 | 88 | snapshotId=$(echo ${createSnapshot} | awk '{print $4}') 89 | 90 | 91 | #echo DEBUG $createSnapshot 92 | #echo DEBUG $snapshotId 93 | #echo DEBUG $snapshotStatus 94 | 95 | echo -n "Creating a snapshot of ${volumeId}..." 96 | 97 | while [ "$snapshotStatus" != "completed" ]; do 98 | echo -n "." 99 | snapshotStatus=$(aws ec2 describe-snapshots --output text --region ${region} --snapshot-id ${snapshotId} | cut -f8) 100 | sleep 2 101 | done 102 | 103 | echo "[OK]" 104 | 105 | # Create a new volume from the snapshot 106 | 107 | echo -n "Creating a new volume from snapshot ${snapshotId}..." 108 | 109 | createVolume=$(aws ec2 create-volume --output text --availability-zone $availabilityZone --snapshot-id ${snapshotId}) 110 | newVolumeId=$(echo ${createVolume} | awk '{print $7}' ) 111 | 112 | unset status 113 | 114 | while [ "$status" != "available" ]; do 115 | echo -n "." 116 | describeVolumes=$(aws ec2 describe-volumes --output text --region ${region} --volume-id ${newVolumeId}) 117 | status=$(echo ${describeVolumes} | awk '{print $7}') 118 | 119 | sleep 2 120 | done 121 | 122 | echo "[OK]" 123 | 124 | 125 | echo -n "Waiting for volume attach operation to complete..." 126 | 127 | attachVolume=$(aws ec2 attach-volume --output text --region ${region} --volume-id ${newVolumeId} --instance-id ${buildId} --device ${mountPoint}) 128 | 129 | if [ "$?" -ne 0 ]; then 130 | echo "The specified region or volumeID is not valid, or the AWS CLI tool is not configured properly." 131 | exit 255 132 | fi 133 | 134 | unset status 135 | 136 | while [ "$status" != "attached" ]; do 137 | echo -n "." 138 | describeVolumes=$(aws ec2 describe-volumes --output text --region ${region} --volume-id ${newVolumeId} | grep 'ATTACHMENTS') 139 | status=$(echo ${describeVolumes} | awk '{print $6}') 140 | mountPoint=$(echo ${describeVolumes} | awk '{print $4}') 141 | 142 | sleep 2 143 | done 144 | 145 | echo "[OK]" 146 | 147 | # Make sure the volume is actually attached 148 | if [ ! -b $mountPoint ]; then 149 | echo "The specified device ${mountPoint} is not available. Exiting." 150 | exit 0 151 | fi 152 | 153 | 154 | echo "Creating image..." 155 | 156 | dd if=${mountPoint} of=${filename} bs=1M status=progress 157 | 158 | if [ ! -f ${filename} ]; then 159 | echo "Image file creation failed. Exiting." 160 | exit 0 161 | fi 162 | 163 | echo -e "\nImage File Contents:\n" 164 | fdisk -lu ${filename} 165 | 166 | echo "Compressing image..." 167 | 168 | gzip ${filename} 169 | 170 | if [ ! -f "${filename}.gz" ]; then 171 | echo "Image file compression failed. Exiting." 172 | exit 0 173 | fi 174 | 175 | echo "Image creation complete." 176 | echo -n "Detaching volume..." 177 | 178 | detachVolume=$(aws ec2 detach-volume --output text --region ${region} --volume-id ${newVolumeId}) 179 | unset status 180 | 181 | while [ "$status" != "available" ]; do 182 | echo -n "." 183 | describeVolumes=$(aws ec2 describe-volumes --output text --region ${region} --volume-id ${newVolumeId} | grep 'VOLUMES') 184 | status=$(echo ${describeVolumes} | awk '{print $7}') 185 | 186 | sleep 2 187 | done 188 | 189 | echo "[OK]" 190 | 191 | # Delete the volume and snapshot created earlier 192 | 193 | echo -n "Deleting the snapshot..." 194 | 195 | deleteSnapshot=$(aws ec2 delete-snapshot --output text --region ${region} --snapshot-id ${snapshotId}) 196 | if [ "$?" -ne 0 ]; then 197 | echo "An error occured while deleting the snapshot:" 198 | echo ${deleteSnapshot} 199 | exit 255 200 | fi 201 | 202 | echo "[OK]" 203 | 204 | echo -n "Deleting the temporary volume..." 205 | 206 | deleteVolume=$(aws ec2 delete-volume --output text --region ${region} --volume-id ${newVolumeId}) 207 | 208 | if [ "$?" -ne 0 ]; then 209 | echo "An error occured while deleting the volume:" 210 | echo ${deleteVolume} 211 | exit 255 212 | fi 213 | 214 | echo "[OK]" 215 | 216 | 217 | # Add in your code to move or copy the image file as needed. As an example... 218 | 219 | echo "Moving ${filename}.gz to Google Drive..." 220 | 221 | #rclone move ${filename}.gz FOSGDrive:/isos/ 222 | 223 | # Done 224 | 225 | echo "Done." 226 | --------------------------------------------------------------------------------