Created
October 21, 2016 02:03
-
-
Save aspring/720a0df5680a7fb8afc599e739f822c1 to your computer and use it in GitHub Desktop.
Modified: https://github.com/blalor/ami-creator/blob/master/utils/create-ami.sh for managing multiple externally built disk images
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
# This script is loosely based off of: https://github.com/blalor/ami-creator/blob/master/utils/create-ami.sh | |
set -e -u | |
die() { | |
echo "$@" | |
exit 1 | |
} | |
# This function displays the usage options for this script | |
usage() { | |
cat << EOF | |
usage: `basename $0` options | |
This script assists in the creation of an Amazon Machine Image from a Disk Image. | |
OPTIONS: | |
-d <image,device,size> The Disk Image, block device, and size comma separated. | |
-h Show this message. | |
-n <name> (Required) The name for the Amazon Machine Image. | |
-s <name> (Required) The S3 bucket for HVM imported volume. | |
-z <name> (Required) The availability zone for the HVM volume. | |
EOF | |
} | |
# Thie function validates the user provided arguments for correctness. | |
validate_arguments() { | |
# Make sure we have at least one disk | |
if [ ${#ARG_DISKS[@]} -eq 0 ]; then | |
die "ERROR: must specify at least one disk." | |
fi | |
# Split the disk strings into pieces | |
for (( i=0; i<${#ARG_DISKS[@]}; i++ )); | |
do | |
ARG_IMAGES+=($(echo ${ARG_DISKS[$i]} | cut -f1 -d,)) | |
ARG_DEVICES+=($(echo ${ARG_DISKS[$i]} | cut -f2 -d,)) | |
ARG_SIZES+=($(echo ${ARG_DISKS[$i]} | cut -f3 -d,)) | |
done | |
# Verify an AMI name was provided | |
[[ ! -z $ARG_NAME ]] || die "ERROR: An AMI name must be provided" | |
if [ ${#ARG_NAME} -lt 3 ] || [ ${#ARG_NAME} -gt 128 ]; then | |
die "ERROR: illegal length for AMI name; must be >= 3, <= 128" | |
fi | |
if echo $ARG_NAME | egrep -q '[^A-Za-z0-9 ()./_-]' ; then | |
die "ERROR: illegal characters in AMI name; must be [A-Za-z0-9 ()./_-]" | |
fi | |
# Verify that the AMI Name is not already in use | |
if [ "$( aws ec2 describe-images --filters "Name=name,Values=${ARG_NAME}" | /usr/local/bin/jq -r '.Images | length' )" -ne 0 ]; then | |
die "ERROR: An AMI with that name already exists!" | |
fi | |
return 0 | |
} | |
# This function validates the environment provided applications and configration for sanity | |
validate_environment() { | |
# Verify this is run as the root user | |
[ $EUID -eq 0 ] || die "ERROR: This script must be run as the 'root' user." | |
# Verify we have the necessary third party tools | |
which aws >/dev/null 2>&1 || die "ERROR: 'aws' not found" | |
which curl >/dev/null 2>&1 || die "ERROR: 'curl' not found" | |
which /usr/local/bin/jq >/dev/null 2>&1 || die "ERROR: 'jq' not found" | |
# Verify AWS environment variables | |
[[ ! -z $AWS_ACCESS_KEY_ID ]] || die "ERROR: AWS_ACCESS_KEY_ID not set" | |
[[ ! -z $AWS_SECRET_ACCESS_KEY ]] || die "ERROR: AWS_SECRET_ACCESS_KEY not set" | |
[ -n $AWS_ACCESS_KEY_ID ] || die "ERROR: AWS_ACCESS_KEY_ID not set" | |
[ -n $AWS_SECRET_ACCESS_KEY ] || die "ERROR: AWS_SECRET_ACCESS_KEY not set" | |
return 0 | |
} | |
# | |
# Script Logic | |
# | |
# Disk related arrays | |
ARG_DISKS=() | |
ARG_DEVICES=() | |
ARG_IMAGES=() | |
ARG_SIZES=() | |
ARG_BUCKET= | |
ARG_KERNEL= | |
ARG_NAME= | |
ARG_REGION= | |
ARG_TYPE= | |
EXTRA_OPTIONS="" | |
# Validate our environment | |
validate_environment | |
while getopts "d:h:n:s:z:" optname | |
do | |
case "$optname" in | |
d) | |
echo "Adding Disk Configuration: $OPTARG" | |
ARG_DISKS+=($OPTARG) | |
;; | |
h) | |
usage | |
exit 1 | |
;; | |
n) | |
echo "Using AMI Name: $OPTARG" | |
ARG_NAME=$OPTARG | |
;; | |
s) | |
echo "Using S3 Bucket: $OPTARG" | |
ARG_BUCKET=$OPTARG | |
;; | |
z) | |
echo "Using AWS Region: $OPTARG" | |
ARG_REGION=$OPTARG | |
;; | |
*) | |
echo "Unknown option -$optname" | |
usage | |
exit 1 | |
;; | |
esac | |
done | |
# Validate our arguments (after we know our region and AZ) | |
validate_arguments | |
VOLUME_ID=() | |
SNAPSHOT_ID=() | |
# Import each of the disk images into EC2 -- storing the volume name | |
for (( i=0; i<${#ARG_IMAGES[@]}; i++ )); | |
do | |
image=${ARG_IMAGES[$i]} | |
echo "Importing the $image into EC2..." | |
conv_id=$(ec2-import-volume -f raw -o $AWS_ACCESS_KEY_ID -w $AWS_SECRET_ACCESS_KEY -b ${ARG_BUCKET} -z ${ARG_REGION} ${image} | grep -o 'import\-vol\-[a-zA-Z0-9]*' -m 1) | |
echo "Waiting for conversion task ${conv_id} to complete (this can take a LONG time)..." | |
while [ $( aws ec2 describe-conversion-tasks --conversion-task-ids ${conv_id} | /usr/local/bin/jq -r '.ConversionTasks[].State' ) != "completed" ]; do | |
sleep 15 | |
done | |
volume_id=$(aws ec2 describe-conversion-tasks --conversion-task-ids ${conv_id} | /usr/local/bin/jq -r '.ConversionTasks[0].ImportVolume.Volume.Id') | |
echo "Tagging ${volume_id}..." | |
aws ec2 create-tags --resources ${volume_id} --tags \ | |
Key=Name,Value="${ARG_NAME}-vol-${i}" \ | |
Key=fedup,Value=1 | |
VOLUME_ID+=("${volume_id}") | |
echo "Conversion task (${conv_id}) completed generating volume ${volume_id}!" | |
done | |
# Create a snapshot of the volume | |
for (( i=0; i<${#VOLUME_ID[@]}; i++ )); | |
do | |
volume_id=${VOLUME_ID[$i]} | |
echo "Creating snapshot of the volume..." | |
snap_id=$( aws ec2 create-snapshot --volume-id ${VOLUME_ID[$i]} --description "Root Image for ${ARG_NAME}" | /usr/local/bin/jq -r .SnapshotId ) | |
echo "Waiting for snapshot ${snap_id} to complete" | |
while [ $( aws ec2 describe-snapshots --snapshot-ids ${snap_id} | /usr/local/bin/jq -r .Snapshots[].State ) != "completed" ]; do | |
sleep 15 | |
done | |
echo "Tagging ${snap_id}..." | |
aws ec2 create-tags --resources ${snap_id} --tags \ | |
Key=Name,Value="${ARG_NAME}-snapshot-${i}" \ | |
Key=fedup,Value=1 | |
SNAPSHOT_ID+=("${snap_id}") | |
echo "Snapshot (${snap_id}) completed!" | |
done | |
# Delete the volumes | |
for (( i=0; i<${#VOLUME_ID[@]}; i++ )); | |
do | |
volume_id=${VOLUME_ID[$i]} | |
echo "Deleting volume ${volume_id}..." | |
$( aws ec2 delete-volume --volume-id ${VOLUME_ID[$i]} ) | |
echo "Volume deletion (${volume_id}) completed!" | |
done | |
# Build the block devive mappings JSON | |
BLOCK_DEVICE_MAPPINGS=() | |
for (( i=0; i<${#SNAPSHOT_ID[@]}; i++ )); | |
do | |
BLOCK_DEVICE_MAPPINGS+=("{\"DeviceName\":\"${ARG_DEVICES[$i]}\",\"Ebs\":{\"SnapshotId\":\"${SNAPSHOT_ID[$i]}\",\"VolumeSize\":${ARG_SIZES[$i]}}}") | |
done | |
IFS=$','; | |
BLOCK_DEVICE_MAPPINGS_STRING="${BLOCK_DEVICE_MAPPINGS[*]}" | |
# | |
# Create an AMI from the snapshot | |
# | |
echo | |
echo "Generating AMI from snapshot..." | |
image_id=$( \ | |
aws ec2 register-image \ | |
--architecture x86_64 \ | |
--name "${ARG_NAME}" \ | |
--root-device-name "${ARG_DEVICES[0]}" \ | |
--block-device-mappings "[${BLOCK_DEVICE_MAPPINGS_STRING}]" \ | |
--virtualization-type hvm \ | |
| /usr/local/bin/jq -r .ImageId | |
) | |
echo "AMI '${ARG_NAME}' created with id ${image_id}" | |
# | |
# Generate a JSON file with all of the relevant information | |
# | |
{ | |
echo "{" | |
echo " \"ami_id\": \"${image_id}\", " | |
echo " \"ami_name\": \"${ARG_NAME}\", " | |
echo " \"virt_type\": \"${ARG_TYPE}\"" | |
echo "}" | |
} > "ami.json" | |
exit 0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment