Skip to content

Instantly share code, notes, and snippets.

Forked from RJ/
Created December 20, 2017 23:14
Show Gist options
  • Save phpdude/a9960321b7172c89a6596ce682497daf to your computer and use it in GitHub Desktop.
Save phpdude/a9960321b7172c89a6596ce682497daf to your computer and use it in GitHub Desktop.
Exporting VMWare images (OVA) from EC2

How to provision VMWare compatible .ova images on EC2

EC2 only lets you export instances as VMWare-compatible OVA files if you originally imported that instance from an OVA. Presumably it preserves the metadata and XML gubbins for the instance, and just wraps it up again using that metadata on export.

In order to provision arbitrary VMs in an OVA-exportable way, we abuse the volume snapshots on one VM.

Prep work:

  • Make a fresh install of ubuntu server or whatever your base distro is, in VMWare, export as OVA file. (single disk only!)
  • Untar the OVA and import the VMDK file into ec2 using ec2-instance-import onto an HVM instance type (ie, no xen kernel needed)
  • Snapshot the volume, make a note of the snapshot ID. This is the "freshly installed ubuntu server" snapshot.

Provisioning an OVA-exportable instance:

  • Stop instance (ec2-stop-instances)
  • Detach existing volume from instance (ec2-detach-volume)
  • Delete existing volume (ec2-delete-volume)
  • Make new volume from $INITIAL_SNAPSHOT_ID (ec2-create-volume)
  • Attach new volume to instance (ec2-attach-volume)
  • Boot instance (ec2-start-instances)
  • Provision (eg: run packer with null builder, run chef, etc)
  • Export instance using ec2-create-instance-export
  • Download your OVA from S3, import to VMWare / Virtualbox
  • Repeat for the next provisioning job.


I have a 100 line shell script as part of a jenkins job that does this to build exportable VM images. You have to block until completion, eg call ec2-create-volume when poll ec2-describe-volumes until your action has completed.

Have fun.

Copy link

phpdude commented Dec 20, 2017

#!/bin/bash -e
export PATH=/var/lib/jenkins/packer:$PATH
test -f ~/.aws/creds.env && source ~/.aws/creds.env
# build VMWare.
# none of the ec2-* commands have a "block until done" option
# so we have to poll the ec2-describe commands in some places
# I made a clean install of ubuntu 14.04 in vmware, with a single disk (no LVM)
# and used amazons import tools.
export instance_id="i-xxxxxx"
# then I made a snapshot of the filesystem in the freshly imported state
export initial_snapshot_id="snap-xxxxxx"
# all this is happening in:
export region="us-west-1"
export availability_zone="us-west-1c"
#1) Ensure instance is stopped
echo "Stopping instance $instance_id"
ec2-stop-instances --region $region $instance_id
until ec2-describe-instances --region $region $instance_id | grep ^INSTANCE | grep stopped
  echo "Waiting for instance to be stopped.."
  sleep 10
#2) Remove EBS volume (ie, so instance has no associated disk)
old_volume_id=$(ec2-describe-instances --region $region $instance_id |
                awk '/^BLOCKDEVICE/ {print $3}')
if [ -n "$old_volume_id" ]
  echo "Deleting old volume $old_volume_id"
  ec2-detach-volume --region $region $old_volume_id -i $instance_id 
  while ec2-describe-volumes --region $region $old_volume_id | grep ^ATTACHMENT
    echo "Waiting for detatchment"
    sleep 5
  ec2-delete-volume --region $region $old_volume_id
  while ec2-describe-volumes --region $region $old_volume_id
    echo "Waiting for volume deletion"
#3) Create new EBS volume from initial snapshot
echo "Making new volume from snapshot $initial_snapshot_id"
export new_volume_id=$(ec2-create-volume \
                  --region $region \
                  --availability-zone $availability_zone \
                  --snapshot $initial_snapshot_id |
                awk '/^VOLUME/ {print $2}')
until ec2-describe-volumes --region $region $new_volume_id | grep ^VOLUME | grep available
  echo "Waiting for volume creation"
  sleep 5
echo "Created new volume: $new_volume_id"
#4) Attach new volume to instance
echo "Attaching new volume to instance"
ec2-attach-volume --region $region $new_volume_id -i $instance_id -d /dev/sda1
until ec2-describe-volumes --region $region $new_volume_id | grep ^ATTACHMENT
  echo "Waiting for volume to attach to instance"
  sleep 5
#5) Boot instance
echo "Starting instance"
ec2-start-instances --region $region $instance_id
until ec2-describe-instance-status --region $region $instance_id | awk '/^INSTANCE/ && $6=="ok" && $7=="ok"' | grep $instance_id
  echo "Waiting for instance to be running"
  sleep 10
#6) Provision like the AMI, using packer's null builder (just ssh -> chef)
packer build -color=false vmware-ec2-provision.json
#7) Export as a VMDK using EC2's export tools
#    (only possible because the instance was imported from VMDK initially)
export export_task_id=$(ec2-create-instance-export-task $instance_id \
                  --region $region \
                  -e vmware \
                  -f vmdk \
                  -c OVA \
                  -b irccloud-vms \
                  -d "exporting vmware inst $(date +%s)" |
                 awk '/^EXPORTTASK/ {print $2}')
until ec2-describe-export-tasks \
        --region $region $export_task_id | grep completed
  echo "Waiting for export task $export_task_id to complete.."
  sleep 30
export export_file=$(ec2-describe-export-tasks --region $region $export_task_id |
              awk '{print $NF}')
echo "Export complete, filename: $export_file, moving buckets"

news3name="irccloud-${ENT_NAME}-$(date +%Y%m%d-%s).ova"
s3cmd mv "s3://irccloud-vms/$export_file" "s3://irccloud-vms/$news3name"

echo "Stopping instance $instance_id, we're done here."
ec2-stop-instances --region $region $instance_id

echo "S3 ASSET: s3://irccloud-vms/$news3name"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment